在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]
屬性的值綁定到指定控件中。
如果你覺得不錯,掃描下面公眾號給個關注,在此感謝!!