如何使用 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,我认为我做对了。
我一定是遗漏了什么,但看不到。我搜索了 ComboBox
、DependencyProperty
、Enum
,找到了一些匹配项,例如 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:Bind
对SelectedMyEnum
不起作用,需要用Binding
写成
<ComboBox
ItemsSource="{x:Bind MyEnums}"
SelectedItem="{Binding SelectedMyEnum,Mode=TwoWay}">
</ComboBox>
和 DataContext
设置为 this
。在我的实验中,这似乎只是 x:Bind
和 TwoWay
绑定的问题,OneWay
和 OneTime
与 x:Bind
的绑定似乎没问题。如果绑定到字符串而不是枚举,这不是问题。
假设我们有
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,我认为我做对了。
我一定是遗漏了什么,但看不到。我搜索了 ComboBox
、DependencyProperty
、Enum
,找到了一些匹配项,例如 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:Bind
对SelectedMyEnum
不起作用,需要用Binding
写成
<ComboBox
ItemsSource="{x:Bind MyEnums}"
SelectedItem="{Binding SelectedMyEnum,Mode=TwoWay}">
</ComboBox>
和 DataContext
设置为 this
。在我的实验中,这似乎只是 x:Bind
和 TwoWay
绑定的问题,OneWay
和 OneTime
与 x:Bind
的绑定似乎没问题。如果绑定到字符串而不是枚举,这不是问题。