代码之家  ›  专栏  ›  技术社区  ›  Peter M

将组合框绑定到类中嵌套的枚举

  •  10
  • Peter M  · 技术社区  · 16 年前

    我非常热衷于将组合框绑定到类的枚举类型属性,在该类中声明枚举本身。

    我正努力按照这里提供的答案来做 (wpf combobox binding to enum what i did wrong?) 具体来说,我使用的是建议的MarkupExtension代码和匹配的XAML代码。

    我的工作代码是:

    在单独的文件中定义枚举。

    namespace EnumTest
    {
        public enum TestEnum {one, two, three, four };
    }
    

    使用枚举的类(请注意,已删除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;
            }
        }
     }
    

    用于显示枚举的扩展方法

    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设计器将不会加载。所以,在我清除XAML错误之前,我一直在做更多的WPF工作。

    我现在想知道这是否是一个vs 2008 SP1的问题,而不是我的问题。

    编辑

    1. 使我的问题陈述更加明确。
    2. 尝试了Joel的第一个解决方案,但最后我还是运行了代码 2个XAML错误
    3. 尝试了乔尔的第二个解决方案,这是直接解决方案-所以我要用那个解决方案!

    笔记 我从中得到markupextension代码的so问题使用了这种类型的语法用于XAML:

    <ComboBox ItemsSource="{w:EnumValues w:TestEnum}"/>
    

    当我使用它时,我得到一个编译错误,说没有EnumValues构造函数接受1个参数。我做了一些谷歌搜索,这似乎是一个错误,在我使用的vs.2008sp1。我确实看到一些评论暗示它是在2010年的测试版。总之,这就是为什么我使用

    <ComboBox ItemsSource="{w:EnumValues EnumType=w:TestEnum}"/>
    

    因为这个语法是有效的!

    2 回复  |  直到 9 年前
        1
  •  3
  •   Joel B Fant    16 年前

    获取用作数据源的枚举值的另一种方法:

    <Window.Resources>
        <ObjectDataProvider
            MethodName="GetValues"
            ObjectType="{x:Type sys:Enum}"
            x:Key="TestValues">
            <ObjectDataProvider.MethodParameters>
                <w:Type2
                    TypeName="w:Test+TestEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    
    ...
    
    ItemsSource="{Binding Source={StaticResource TestValues}}"
    

    请注意,您仍然需要 Type2Extension 因为奇怪 TypeExtension 和嵌套类型。但是您不需要额外的自定义标记扩展。如果您要在多个地方使用该列表,这种方法会更好,因为您可以在 App.xaml 资源。

        2
  •  1
  •   Joel B Fant    16 年前

    用什么呢 x:Type 标记扩展?

    {w:EnumValues EnumType={x:Type w:Test+TestEnum}}
    

    除了执行 INotifyPropertyChanged ,我完全复制了你的代码。我确实得到了你得到的错误,但它似乎运行得很好。不过,如果不能加载设计器,那就很烦人了。我所做的一切都没有解决这个问题。

    我确实找到了 this page 在msdn上关于嵌套类型,该线程中的建议是 MarkupExtension 用于解析嵌套类型名。我正在努力让它工作,但到目前为止还没有运气。我也有类似的错误 Type2Extension 有时,我会得到“枚举类型没有设置”和其他调整。

    啊哈!原来的作者打电话的方式有一个错误 GetType() !这是更正的 2型扩展 我是如何使用它的:

    public class Type2Extension : System.Windows.Markup.TypeExtension {
        public Type2Extension() {
        }
    
        public Type2Extension( string typeName ) {
            base.TypeName = typeName;
        }
    
        public override object ProvideValue( IServiceProvider serviceProvider ) {
            IXamlTypeResolver typeResolver = (IXamlTypeResolver) serviceProvider.GetService( typeof( IXamlTypeResolver ) );
            int sepindex = TypeName.IndexOf( '+' );
            if ( sepindex < 0 )
                return typeResolver.Resolve( TypeName );
            else {
                Type outerType = typeResolver.Resolve( TypeName.Substring( 0, sepindex ) );
                return outerType.Assembly.GetType( outerType.FullName + "+" + TypeName.Substring( sepindex + 1 ) );
            }
        }
    }
    

    和XAML:

    ItemsSource="{Binding Source={w:EnumValues {w:Type2 w:Test+TestEnum}}}"
    

    这似乎工作得很好,设计师也很忙。我将加入 2型扩展 去我自己的小图书馆。

    编辑: 奇怪的是,如果我把这个换成 EnumValues :

    if ( this.EnumType == null )
        throw new ArgumentException( "The enum type is not set" );
    

    对此:

    if ( this.EnumType == null )
        return null;
    

    然后那些构造函数错误就消失了。那是我改变的另一件事。不过,我很快将发布获取枚举值的另一种方法。