在WPF中一種較好的綁定Enums數(shù)據(jù)方法


引言
在你使用wpf應用程序開發(fā)的時候,是否需要進行數(shù)據(jù)綁定到Enum數(shù)據(jù)呢?在這篇文章中,我將向你展示在WPF中處理Enum數(shù)據(jù)綁定的方法。
假設存在一個這樣的Enum數(shù)據(jù)的定義,具體內(nèi)容如下文代碼中所示:
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 創(chuàng)建一個ObjectDataProvider資源
在此步驟中,你需要創(chuàng)建一個ObjectDataProvider的資源,并給它一個鍵名x:Key="DataFromEnum",這樣就可以使用DataFromEnum在代碼中使用它。并且你需要給MethodName設置為Enum類型上存在的GetValues,然后將ObjectType設置為Enum類型。接下來,你將需設置ObjectDataProvider.MethodParameters的Enum類型。最后,你添加的ObjectDataProvider資源如下面代碼所示
????
????????????????????x:Key="DataFromEnum"
????????????MethodName="GetValues"
????????????ObjectType="{x:Type?sys:Enum}">
????????????
????????????????"local:Status">
????????????????
????????????
????????
????
1.3 Binding數(shù)據(jù)處理
現(xiàn)在,你可以使用數(shù)據(jù)綁定了。例如,想將數(shù)據(jù)綁定到ComboBox上面,那么你需要設置ItemSource為一個新的綁定,并將數(shù)據(jù)源綁定到我們上面定義的名為DataFromEnum的資源。
????
????????????????????MinWidth="150"
????????????HorizontalAlignment="Center"
????????????VerticalAlignment="Center"
????????????ItemsSource="{Binding?Source={StaticResource?DataFromEnum}}">
????????
????
到現(xiàn)在為止,所有的已經(jīng)處理完成,運行程序可以看到數(shù)據(jù)已經(jīng)正確綁定到ComboBox上面。
二、較好的處理方法
讓我們來看看當數(shù)據(jù)綁定Enum類型時,如何使用WPF特性來改進代碼的使用和可讀性。首先,想封裝Enum類型的綁定而不需要ObjectDataProvider資源的邏輯處理,還希望不需要必須定義資源才能在xaml中使用綁定功能。理想情況下,應該像處理普通對象的綁定一樣,將所有內(nèi)容都內(nèi)聯(lián)處理。為此,需要利用定制MarkupExtension的幫助類。這個擴展將簡單的接受Enum類型,然后為控件創(chuàng)建一個可綁定Enum值的列表,這種實現(xiàn)其實很簡單。
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數(shù)據(jù)處理
????
????????
????????????????????????????MinWidth="150"
????????????????HorizontalAlignment="Center"
????????????????ItemsSource="{Binding?Source={StaticResource?DataFromEnum}}">
????????????
????????????????????????????MinWidth="150"
????????????????HorizontalAlignment="Center"
????????????????ItemsSource="{Binding?Source={local:EnumBindingSource?{x:Type?local:Status}}}">
????????????
????????
????
看一下運行結(jié)果:

三、擴展:添加Enum類型的描述(Description)支持
現(xiàn)在我們可以不用使用ObjectDataProvider資源進行Enum類型的綁定工作了。這兩種方法進行對比一下,詳細這個新方法會讓你耳目一新,像發(fā)現(xiàn)了新大陸一般。
而Enum類型的值一般使用在程序中,而為了讓用戶獲得更好的使用體驗,一般都會在枚舉值前面添加上屬性:Description描述。為了完成此工作,我們只需使用TypeConverter進行轉(zhuǎn)換。
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
????}
}
程序運行結(jié)果:
可以看到,我們添加了[Description]屬性時,這兩種方法都可以將[Description]屬性的值綁定到指定控件中。
如果你覺得不錯,掃描下面公眾號給個關注,在此感謝!!

