Suppose we have
public enum MyEnum {None, First, Second}
and in MainWindow.xaml.cs, we have
private IList<MyEnum> _myEnums = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();
public IList<MyEnum> MyEnums => _myEnums;
public MyEnum SelectedMyEnum {get;set;}
and in MainWindow.xaml we have
<StackPanel>
<ComboBox ItemsSource="{x:Bind MyEnums}" SelectedItem="{x:Bind SelectedMyEnum, Mode=TwoWay}"/>
</StackPanel>
This works, as expected.
Now suppose we want to replace ComboBox with a user control, i.e.
<local:ExampleControl MyEnums="{x:Bind MyEnums}" SelectedMyEnum="{x:Bind SelectedMyEnum, Mode=TwoWay}"/>
So, in ExampleControl.xaml we have
<StackPanel>
<ComboBox
ItemsSource="{x:Bind MyEnums}"
SelectedItem="{x:Bind SelectedMyEnum,Mode=TwoWay}">
</ComboBox>
</StackPanel>
and in ExampleControl.xaml.cs
we have
// SelectedMyEnum
public static readonly DependencyProperty SelectedMyEnumProperty =
DependencyProperty.Register(
"SelectedMyEnum",
typeof(MyEnum),
typeof(ExampleControl),
new PropertyMetadata(MyEnum.None)); // (1)
public MyEnum SelectedMyEnum
{
get { return (MyEnum)GetValue(SelectedMyEnumProperty); }
set { SetValue(SelectedMyEnumProperty, value); } // (2)
}
// MyEnums
public static readonly DependencyProperty MyEnumsProperty =
DependencyProperty.Register(
"MyEnums",
typeof(IEnumerable<MyEnum>),
typeof(ExampleControl), null
);
public IEnumerable<MyEnum> MyEnums
{
get { return (IEnumerable<MyEnum>)GetValue(MyEnumsProperty); }
set { SetValue(MyEnumsProperty, value); }
}
But this doesn't work. On startup, the SelectedMyEnum setter (2) is called repeatedly with the value MyEnum.None until there is a stack overflow,
System.StackOverflowException
HResult=0x800703E9
Source=<Cannot evaluate the exception source>
StackTrace:
<Cannot evaluate the exception stack trace>
In (1), in place of
new PropertyMetadata(MyEnum.None)
I tried
new PropertyMetadata(MyEnum.None, OnEnumChanged)
with
private static void OnEnumChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var control = (ExampleControl)obj;
MyEnum myVal = (MyEnum)args.NewValue; // (3)
}
but that made no difference, the function OnEnumChanged was called repeatedly, along with the setter, with myVal == MyEnum.None, until stack overflow.
I checked the WinUI Gallery for examples of dependency properties for enums, but couldn't find any, but there were plenty of examples for double, int, and bool, e.g. ItemHeight in WrapPanel, I think I'm doing this right.
I must be missing something, but can't see it. I've searched on ComboBox, DependencyProperty, Enum, and found some matches, e.g Enum as a DependencyProperty of a UserControl, but I didn't find them helpful. Any help is appreciated.
Note that if I change MyEnum to string in the control, and bind to an array of strings for the items source and a string for the selected item, everything works as expected, with no other changes. I can obviously work around this, but I would like to understand what's going on with enum and dependency properties, which is my preferred way to implement this.
Environment:
Microsoft Visual Studio Community 2022
Version 17.1.0
VisualStudio.17.Release/17.1.0+32210.238
Microsoft .NET Framework
Version 4.8.04161