• 在WPF中一种较好的绑定Enums数据方法


    引言

    在你使用wpf应用程序开发的时候,是否需要进行数据绑定到Enum数据呢?在这篇文章中,我将向你展示在WPF中处理Enum数据绑定的方法。

    假设存在一个这样的Enum数据的定义,具体内容如下文代码中所示:

    namespace LocalizeFrameworkWpfApp
    {
        public enum Status
        {
            Horrible,
            Bad,
            SoSo,
            Good,
            Better,
            Best
        }
    }
    

    一、WPF中的通常处理方法

    1.1 添加引用

    MainWindow.xaml文件中从mscorlib中引入命名空间System

    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    

    1.2 创建一个ObjectDataProvider资源

    在此步骤中,你需要创建一个ObjectDataProvider的资源,并给它一个键名x:Key="DataFromEnum",这样就可以使用DataFromEnum在代码中使用它。并且你需要给MethodName设置为Enum类型上存在的GetValues,然后将ObjectType设置为Enum类型。接下来,你将需设置ObjectDataProvider.MethodParametersEnum类型。最后,你添加的ObjectDataProvider资源如下面代码所示

        <Window.Resources>
            <ObjectDataProvider
                x:Key="DataFromEnum"
                MethodName="GetValues"
                ObjectType="{x:Type sys:Enum}">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="local:Status">
                    </x:Type>
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
        </Window.Resources>
    

    1.3 Binding数据处理

    现在,你可以使用数据绑定了。例如,想将数据绑定到ComboBox上面,那么你需要设置ItemSource为一个新的绑定,并将数据源绑定到我们上面定义的名为DataFromEnum的资源。

        <Grid>
            <ComboBox
                MinWidth="150"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                ItemsSource="{Binding Source={StaticResource DataFromEnum}}">
            </ComboBox>
        </Grid>
    

    到现在为止,所有的已经处理完成,运行程序可以看到数据已经正确绑定到ComboBox上面。

    二、较好的处理方法

    让我们来看看当数据绑定Enum类型时,如何使用WPF特性来改进代码的使用和可读性。首先,想封装Enum类型的绑定而不需要ObjectDataProvider资源的逻辑处理,还希望不需要必须定义资源才能在xaml中使用绑定功能。理想情况下,应该像处理普通对象的绑定一样,将所有内容都内联处理。为此,需要利用定制MarkupExtension的帮助类。这个扩展将简单的接受Enum类型,然后为控件创建一个可绑定Enum值的列表,这种实现其实很简单。

    2.1 MarkupExtension帮助类

    MarkupExtension帮助类定义如下:

    namespace LocalizeFrameworkWpfApp
    {
        public class EnumBindingSourceExtension:MarkupExtension
        {
            private Type _enumType;
    
            public Type EnumType
            {
                get { return _enumType; }
                set
                {
                    if (value != _enumType)
                    {
                        if (null != value)
                        {
                            var enumType = Nullable.GetUnderlyingType(value) ?? value;
                            if (!enumType.IsEnum)
                            {
                                throw new ArgumentException("Type must bu for an Enum");
                            }
    
                        }
    
                        _enumType = value;
                    }
                }
            }
    
            public EnumBindingSourceExtension()
            {
                
            }
    
            public EnumBindingSourceExtension(Type enumType)
            {
                EnumType = enumType;
            }
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                if (null == _enumType)
                {
                    throw  new InvalidOperationException("The EnumTYpe must be specified.");
                }
    
                var actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType;
                var enumValues = Enum.GetValues(actualEnumType);
    
                if (actualEnumType == _enumType)
                {
                    return enumValues;
                }
    
                var tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
                enumValues.CopyTo(tempArray, 1);
    
                return tempArray;
            }
        }
    }
    

    2.2 Binding数据处理

        <Grid>
            <StackPanel>
                <ComboBox
                    MinWidth="150"
                    HorizontalAlignment="Center"
                    ItemsSource="{Binding Source={StaticResource DataFromEnum}}">
                </ComboBox>
                <ComboBox
                    MinWidth="150"
                    HorizontalAlignment="Center"
                    ItemsSource="{Binding Source={local:EnumBindingSource {x:Type local:Status}}}">
                </ComboBox>
            </StackPanel>
        </Grid>
    

    看一下运行结果:

    三、扩展:添加Enum类型的描述(Description)支持

    现在我们可以不用使用ObjectDataProvider资源进行Enum类型的绑定工作了。这两种方法进行对比一下,详细这个新方法会让你耳目一新,像发现了新大陆一般。

    Enum类型的值一般使用在程序中,而为了让用户获得更好的使用体验,一般都会在枚举值前面添加上属性:Description描述。为了完成此工作,我们只需使用TypeConverter进行转换。

    namespace LocalizeFrameworkWpfApp
    {
        public class EnumDescriptionTypeConverter:EnumConverter
        {
            public EnumDescriptionTypeConverter(Type type) : base(type)
            {
            }
    
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                if (destinationType == typeof(string))
                {
                    if (null != value)
                    {
                        FieldInfo fi = value.GetType().GetField(value.ToString());
    
                        if (null != fi)
                        {
                            var attributes =
                                (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    
                            return ((attributes.Length > 0) && (!string.IsNullOrEmpty(attributes[0].Description)))
                                ? attributes[0].Description
                                : value.ToString();
                        }
                    }
    
                    return string.Empty;
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }
    }
    

    然后对定义的枚举值添加上[Description]属性

    namespace LocalizeFrameworkWpfApp
    {
        [TypeConverter(typeof(EnumDescriptionTypeConverter))]
        public enum Status
        {
            [Description("This is horrible")]
            Horrible,
            [Description("This is Bad")]
            Bad,
            [Description("This is SoSo")]
            SoSo,
            [Description("This is Good")]
            Good,
            [Description("This is Better")]
            Better,
            [Description("This is Best")]
            Best
        }
    }
    
    

    程序运行结果:

    可以看到,我们添加了[Description]属性时,这两种方法都可以将[Description]属性的值绑定到指定控件中。

    如果你觉得不错,扫描下面公众号给个关注,在此感谢!!

  • 相关阅读:
    详细版Jmeter随机参数的接口并发测试总结
    Windows下MQTT代理服务器的搭建
    关于使用elascticsearch的两个小技巧
    解决easyswoole的swServer_start_check: onTask event callback must be set at报错
    解决使用宝塔安装的swoole扩展,运行项目出现的3个常见问题
    浅谈一下ThinkPHP5.1实现事务嵌套的特性
    资源出现多个 "Access-Control-Allow-Origin"
    Mac 制作系统启动盘
    深入剖析分布式一致性共识算法
    分布式系统限流算法分析与实现
  • 原文地址:https://www.cnblogs.com/sesametech-netcore/p/13878443.html
Copyright © 2020-2023  润新知