在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.MethodParameters的Enum类型。最后,你添加的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]属性的值绑定到指定控件中。
如果你觉得不错,扫描下面公众号给个关注,在此感谢!!

在WPF中一种较好的绑定Enums数据方法的更多相关文章
- WPF中的ListBox实现按块显示元素的方法
		本文实例讲述了WPF中的ListBox实现按块显示元素的方法.分享给大家供大家参考,具体如下: 注意:需要设置ListBox的属性 ScrollViewer.HorizontalScrollBarVi ... 
- WPF中ItemsControl应用虚拟化时找到子元素的方法
		原文:WPF中ItemsControl应用虚拟化时找到子元素的方法 wpf的虚拟化技术会使UI的控件只初始化看的到的子元素, 而不是所有子元素都被初始化,这样会提高UI性能. 但是我们经常会遇到一个 ... 
- 整理:WPF中应用附加事件制作可以绑定命令的其他事件
		原文:整理:WPF中应用附加事件制作可以绑定命令的其他事件 目的:应用附加事件的方式定义可以绑定的事件,如MouseLeftButton.MouseDouble等等 一.定义属于Control的附加事 ... 
- 转:WPF中ListBox的创建和多种绑定用法
		先从最容易的开始演示ListBox控件的创建. Adding ListBox Items下面的代码是向ListBox控件中添加多项ListBoxItem集合.XAML代码如下:<ListBox ... 
- WPF中使用相对资源来进行绑定,数据源是通过DataContext来指定的
		1. 最外层是Window是对象,Window的ItemsControl使用了ItemsTemplate,然后在ItemsTemplate中要绑定Language属性, 而整个Window的数据源是通 ... 
- WPF中三种方法得到当前屏幕的宽和高
		WPF程序中的单位是与设备无关的单位,每个单位是1/96英寸,如果电脑的DPI设置为96(每个英寸96个像素),那么此时每个WPF单位对应一个像素,不过如果电脑的DPI设备为120(每个英寸120个像 ... 
- .Net中几种常见的页面跳转传值方法
		1.ASP Server对象Execute方法 ASP Server对象的Execute方法可以在执行当前页面的过程中将另一个页面执行结果的内容插入到当前页面的输出中.Execute方法带一个参数,是 ... 
- android在代码中四种设置控件背景颜色的方法(包含RGB)
		转载请注明出处: http://blog.csdn.net/fth826595345/article/details/9208771 TextView tText=(TextView) findVi ... 
- Javascript中两种最通用的定义类的方法
		在Javascript中,一切都是对象,包括函数.在Javascript中并没有真正的类,不能像C#,PHP等语言中用 class xxx来定义.但Javascript中提供了一种折中的方案:把对象定 ... 
随机推荐
- 类加载器ClassLoader
			上篇文章说到,Class类可以通过一个类的全限定名去加载类,那么底层是如何去加载的呢?这就是我们今天要聊的类加载器ClassLoader,其可以通过一个类的全限定名来获取描述此类的二进制字节流,也即是 ... 
- 【测试基础第六篇】bug定义及生命周期
			bug定义 狭义:软件程序的漏洞或缺陷 广义:测试工程师或用户所发现和提出的软件可改进的细节(增强型.建议性)或需求文档存在差异的功能实现 职责:发现bug,提给开发,让其修改 bug类型--了解 代 ... 
- 使用VMware虚拟机安装RHEL7(RedHat Enterprise Linux7)步骤
			准备工具: 1.VMware Workstation 14 2.RedHat Enterprise Linux 7.0镜像文件 在虚拟机内设置操作系统的硬件标准 单击"创建新的虚拟机&quo ... 
- tomcat源码--springboot整合tomcat源码分析
			1.测试代码,一个简单的springboot web项目:地址:https://gitee.com/yangxioahui/demo_mybatis.git 一:tomcat的主要架构:1.如果我们下 ... 
- Oracle Database XE 11gR2 SQL 命令行的显示调整
			操作系统:Windows 10 x64 Oracle Database XE 11gR2 参考:在cmd命令行使用sqlplus时的页面显示问题 通过 cmd 命令行或运行 SQL 命令行查看一张表的 ... 
- regsvr32 bypass windows defender 新思路
			原文链接:blog 在对regsvr32的用法进行了解之后,对于Casey Smith的远程js脚本执行命令的思路很感兴趣. 命令语法如下: regsvr32 /s /n /u /i:http://1 ... 
- linux的安装3.7python
			centos安装python3 首先安装依赖包 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-dev ... 
- element Ui的级联选择器 任意一级选中下拉框自动关闭
			封装成一个子组件 <template> <el-cascader v-model="value" clearable placeholder="请选择& ... 
- protoc-c 阅读笔记
			以前和山哥做过类似的,最近想起来,抽空又看了下 protoc-c. 山哥做的报文流向: rpc -> lydtree -> motree -> struct 涉及的细节很多 1) l ... 
- [CISCN2019 华北赛区 Day2 Web1]Hack World 1详解
			打开题目, 我们开始尝试注入, 输入0回显Error Occured When Fetch Result. 输入1回显Hello, glzjin wants a girlfriend. 输入2回显Do ... 
