如何使用 ComboBox、Enum 和 DependencyProperty 实现 WinUI 3 UserControl

How to implement a WinUI 3 UserControl with ComboBox, Enum and DependencyProperty

假设我们有

public enum MyEnum {None, First, Second}

MainWindow.xaml.cs 中,我们有

private IList<MyEnum> _myEnums = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();
public IList<MyEnum> MyEnums => _myEnums;

public MyEnum SelectedMyEnum {get;set;} 

MainWindow.xaml中我们有

<StackPanel>
    <ComboBox ItemsSource="{x:Bind MyEnums}" SelectedItem="{x:Bind SelectedMyEnum, Mode=TwoWay}"/>
</StackPanel>

正如预期的那样有效。

现在假设我们要用用户控件替换 ComboBox,即

<local:ExampleControl MyEnums="{x:Bind MyEnums}" SelectedMyEnum="{x:Bind SelectedMyEnum, Mode=TwoWay}"/>

所以,在 ExampleControl.xaml 我们有

<StackPanel>
    <ComboBox 
      ItemsSource="{x:Bind MyEnums}"
      SelectedItem="{x:Bind SelectedMyEnum,Mode=TwoWay}">
    </ComboBox>
</StackPanel>

ExampleControl.xaml.cs中我们有

// 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); }
}

但这不起作用。启动时,SelectedMyEnum setter (2) 被重复调用,值为 MyEnum.None 直到堆栈溢出,

System.WhosebugException
  HResult=0x800703E9
  Source=<Cannot evaluate the exception source>
  StackTrace:
<Cannot evaluate the exception stack trace>

而不是 (1) 中的 new PropertyMetadata(MyEnum.None),我尝试了

new PropertyMetadata(MyEnum.None, OnEnumChanged)

private static void OnEnumChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 
{
    var control = (ExampleControl)obj;
    MyEnum myVal = (MyEnum)args.NewValue;
}

但这没有什么区别,函数 OnEnumChanged 与 setter、myVal == MyEnum.None 一起被重复调用,直到堆栈溢出。

我检查了 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,我认为我做对了。

我一定是遗漏了什么,但看不到。我搜索了 ComboBoxDependencyPropertyEnum,找到了一些匹配项,例如 Enum as a DependencyProperty of a UserControl,但我没有发现它们有帮助。感谢任何帮助。

环境:

Microsoft Visual Studio Community 2022
Version 17.1.0
VisualStudio.17.Release/17.1.0+32210.238
Microsoft .NET Framework
Version 4.8.04161

已由 Roy Li - MSFT 在 Microsoft 问答网站上回答 here。它与 x:Bind 标记扩展中的 WinUI 缺陷有关。在用户控件中,在enums的情况下,x:BindSelectedMyEnum不起作用,需要用Binding写成

<ComboBox 
  ItemsSource="{x:Bind MyEnums}"
  SelectedItem="{Binding SelectedMyEnum,Mode=TwoWay}">
</ComboBox>

DataContext 设置为 this。在我的实验中,这似乎只是 x:BindTwoWay 绑定的问题,OneWayOneTimex:Bind 的绑定似乎没问题。如果绑定到字符串而不是枚举,这不是问题。