将 ComboBox 绑定到嵌套在类中的枚举
我一直热衷于将组合框绑定到类的枚举类型属性,其中枚举本身是在同一个类中声明的。
我正在尝试遵循此处提供的答案 (wpf 组合框绑定到枚举我做错了什么?) 具体来说,我正在使用建议的 MarkupExtension 代码和匹配的 xaml 代码。
我的工作代码是:
在单独的文件中定义枚举。
namespace EnumTest
{
public enum TestEnum {one, two, three, four };
}
使用 Enum 的类(请注意,已删除 propertyChanged 代码以简化操作):
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
使用该类的程序文件:
namespace EnumTest
{
public partial class Window1 : Window
{
Test _oTest = new Test();
public Window1()
{
InitializeComponent();
cmbBox.DataContext = _oTest;
}
}
}
用于显示 Enum 的扩展方法
namespace EnumTest
{
[MarkupExtensionReturnType(typeof(object[]))]
public class EnumValuesExtension : MarkupExtension
{
public EnumValuesExtension()
{
}
public EnumValuesExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.EnumType == null)
throw new ArgumentException("The enum type is not set");
return Enum.GetValues(this.EnumType);
}
}
}
以及用于显示数据的 xaml 代码:
<Window x:Class="EnumTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:EnumTest"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox Name="cmbBox"
Height="20"
Width="80"
ItemsSource="{Binding Source={w:EnumValues EnumType=w:TestEnum}}"
SelectedItem="{Binding Path=MyVar}"
/>
</Grid>
</Window>
以上都很好,并且花花公子,但我想在测试类中定义枚举,并避免在全局范围内定义枚举。 像这样:
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
// Declare Enum **INSIDE** the class
public enum TestEnum {one, two, three, four };
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
我提到的SO问题暗示了匹配的xaml语法是:
<ComboBox Name="cmbBox"
...
ItemsSource="{Binding Source={w:EnumValues EnumType=w:Test+TestEnum}}"
...
/>
但这(某种程度上)对我不起作用。 当我进行干净构建时,我在 VS 2008 状态栏上收到“构建成功”消息,但我还在 xaml 中报告了错误,
Type 'Test+TestEnum' was not found.
但代码按预期运行!
然而,这意味着 xaml 设计器将不会加载。 所以我有点搞砸了做更多的 wpf 工作,直到我可以清除 xaml 错误。
我现在想知道这是否是 VS 2008 SP1 的问题,而不是我的问题。
编辑
- 使我的问题陈述更加明确。
- 尝试了乔尔的第一个解决方案,但我最终得到了代码运行和 2个xaml错误
- 尝试了乔尔的第二个解决方案,并且直接开箱即用 - 所以我将使用那个!
注释 我从中获得 MarkupExtension 代码的 SO 问题使用了这种 xaml 语法风格:
<ComboBox ItemsSource="{w:EnumValues w:TestEnum}"/>
当我使用它时,我收到一个编译错误,指出没有 EnumValues 构造函数需要 1 个参数。 我做了一些谷歌搜索,这似乎是 VS 中的一个错误。 我使用的是 VS 2008 SP1。 我确实看到一些评论暗示它在 VS 2010 beta 中。 不管怎样,这就是为什么我使用 xaml 语法的原因,
<ComboBox ItemsSource="{w:EnumValues EnumType=w:TestEnum}"/>
因为此语法有效!
I have been going crazy with binding a combobox to an enum typed property of a class, where the enum itself is declared in that same class.
I am trying to follow the answer provided here (wpf combobox binding to enum what i did wrong?) Specifically I am using the suggested MarkupExtension code and the matching xaml code.
My working code is:
Defining the Enum in a separate file.
namespace EnumTest
{
public enum TestEnum {one, two, three, four };
}
Class that uses the Enum (Note that the propertyChanged code has been removed to simplify things):
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
Program file that uses the class:
namespace EnumTest
{
public partial class Window1 : Window
{
Test _oTest = new Test();
public Window1()
{
InitializeComponent();
cmbBox.DataContext = _oTest;
}
}
}
Extension method for displaying the Enum
namespace EnumTest
{
[MarkupExtensionReturnType(typeof(object[]))]
public class EnumValuesExtension : MarkupExtension
{
public EnumValuesExtension()
{
}
public EnumValuesExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.EnumType == null)
throw new ArgumentException("The enum type is not set");
return Enum.GetValues(this.EnumType);
}
}
}
And the xaml code that is used to display the data:
<Window x:Class="EnumTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:w="clr-namespace:EnumTest"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox Name="cmbBox"
Height="20"
Width="80"
ItemsSource="{Binding Source={w:EnumValues EnumType=w:TestEnum}}"
SelectedItem="{Binding Path=MyVar}"
/>
</Grid>
</Window>
The above is all good and dandy, but I want to define the Enum within the Test class and ditch the Enum from being defined at the global scope. Like so:
namespace EnumTest
{
public class Test : INotifyPropertyChanged
{
// Declare Enum **INSIDE** the class
public enum TestEnum {one, two, three, four };
private TestEnum _MyVar;
public TestEnum MyVar {
get { return _MyVar; }
set
{
_MyVar = value;
OnPropertyChanged("MyVar");
}
}
public Test()
{
_MyVar = TestEnum.three;
}
}
}
The SO question I referred to alludes to the matching xaml syntax as being:
<ComboBox Name="cmbBox"
...
ItemsSource="{Binding Source={w:EnumValues EnumType=w:Test+TestEnum}}"
...
/>
But this (sort of) does not work for me. When I do a clean build I get a "Build succeeded" message on the VS 2008 status bar, but I also get an error being reported in the xaml
Type 'Test+TestEnum' was not found.
But the code runs as expected!
However this means that the xaml designer will not load. So I am sort of screwed in doing any more wpf work until I can clear the xaml error.
I am now wondering if this is a VS 2008 SP1 issue, and not a problem on my part.
Edit
- Made my problem statement more explicit.
- Tried Joel's 1st solution, but I ended up with the code running and 2 xaml errors
- Tried Joel's 2nd solution and that worked straight out of the box - so I am going with that one!
Notes
The SO question that I got the MarkupExtension code from uses this style of syntax for the xaml:
<ComboBox ItemsSource="{w:EnumValues w:TestEnum}"/>
When I use that I get a compilation error saying that no EnumValues constructor takes 1 parameter. I did some googling and this seems to be an error in VS. I Am using VS 2008 SP1. I did see some comments that alluded to it being in the VS 2010 beta. Anyway, that is why I use the xaml syntax of
<ComboBox ItemsSource="{w:EnumValues EnumType=w:TestEnum}"/>
As this syntax works!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
获取用作数据源的枚举值的另一种方法:
请注意,由于
TypeExtension
和嵌套类型的奇怪之处,您仍然需要Type2Extension
。 但您不需要额外的自定义标记扩展。 如果您要在多个位置使用该列表,这种方法会更好,因为您可以在App.xaml
资源中声明它。Another way of getting the enum values for use as a data source:
Note that you still need the
Type2Extension
because of weirdness withTypeExtension
and nested types. But you wouldn't need the extra custom markup extension. This way is better if you'll be using the list in multiple places, as you can declare it in yourApp.xaml
resources.使用x:Type
标记扩展怎么样?除了实现
INotifyPropertyChanged
之外,我完全复制了您的代码。 我确实遇到了您遇到的错误,但它似乎运行得很好。 不过,无法加载设计器是非常烦人的。 我尝试过的任何方法都没有解决问题。我确实找到了此页面< /a> 在 MSDN 上有关嵌套类型的内容,该线程中的建议是用于解析嵌套类型名称的自定义
MarkupExtension
。 我正在努力让它发挥作用,但到目前为止还没有运气。 有时,我在Type2Extension
上遇到类似的错误,并且通过其他调整得到“未设置枚举类型”。啊哈! 原作者调用
GetType()
的方式存在错误! 以下是更正后的Type2Extension
以及我如何使用它:XAML:
这似乎工作正常并且设计器加载。 我将把
Type2Extension
添加到我自己的小库中。编辑:奇怪的是,如果我在
EnumValues
中将其更改为:那么
这些构造函数错误就会消失。 这是我改变的另一件事。 不过,我很快就会发布另一种获取枚举值的方法。
What about usingx:Type
markup extension?Except for implementing
INotifyPropertyChanged
, I copied your code exactly. I do get the errors that you get, but it seems to run just fine. It is very annoying not to be able to load the designer, though. Nothing I've tried has solved the problem.I did find this page on MSDN about nested types, and a suggestion in that thread was a custom
MarkupExtension
for resolving the nested type name. I'm trying to get it to work, but no luck so far. I get similar errors onType2Extension
sometimes, and I get "The enum type is not set" with other tweaks.Aha! There was a bug in how the original author was calling
GetType()
! Here's the correctedType2Extension
and how I was using it:And XAML:
This appears to work fine and the designer loads. I'll be adding
Type2Extension
to my own little libraries.Edit: Oddly enough, if I change this in
EnumValues
:To this:
Then those constructor errors go away. That was the one other thing I changed. However, I am shortly going to post an alternate way of getting enum values.