枚举对于定义值列表非常有用。当这些值要在图形界面中显示时,很快就会意识到技术名称和要显示的名称是不同的。此外,有时必须将界面翻译成多种语言。因此,您需要一种机制来解决这一问题。
让我们从定义枚举开始:
public enum Week
{
[Display(ResourceType = typeof (Resources), Name = "TestEnum_First")]
First,
[Display(ResourceType = typeof(Resources), Name = "TestEnum_Second")]
Second,
[Display(ResourceType = typeof(Resources), Name = "TestEnum_Third")]
Third,
[Display(ResourceType = typeof(Resources), Name = "TestEnum_Fourth")]
Fourth,
[Display(ResourceType = typeof(Resources), Name = "TestEnum_Last")]
Last
}
对于每个值,我们使用[Display]
属性定义一个自定义名称。通过此属性,可以定义直接显示或通过资源显示的名称。然后可以使用反射来恢复此属性的值:
Array enumValues = type.GetEnumValues();
foreach (object enumValue in enumValues)
{
var fieldInfo = type.GetField(enumValue.ToString());
DisplayAttribute displayAttribute = fieldInfo.GetCustomAttribute();
if (displayAttribute != null)
{
string name = displayAttribute.GetName();
}
else
{
string name = enumValue.ToString();
}
}
现在让我们看一下WPF的功能:
没有奇迹,显示的值是“第二”。我们将编写一个转换器,使用该Display
属性将值转换为文本。
[ValueConversion(typeof(Enum), typeof(string))]
public class EnumValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var enumValue = value as Enum;
if (enumValue != null)
{
// see the full code here: https://gist.github.com/meziantou/90730189693205fbf9d0
return LocalizationUtilities.GetEnumMemberLocalization(enumValue);
}
return string.Format("{0}", value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
我们可以在XAML中使用此Converter:
我们已经处理了单个值的情况。另一个常见的需求是在ComboBox中显示枚举值的列表。MSDN告诉我们如何使用ObjectDataProvider调用XAML中的方法Enum.GetValues(typeof(Week))
:
我们走到了尽头,但这很罗word(13行)。为简化起见,您可以创建一个DataProvider
而不是ObjectDataProvider
上面的来获取一些行,但是我们可以做得更好😉
标记扩展经常在不知道其含义的情况下使用。其实每次使用时间{Binding}
,{StaticResource}
或者{x:Type}
,您可以使用MarkupExtension
。MarkupExtensions的目的是允许您表达xml只不允许表达的内容。例如,用xaml表示空值很复杂,因此{x:Null}
。它们还使表达复杂的事物变得容易,并减少了我们代码的冗长性。可以想象,您可以编写自己的MarkupExtension:
[MarkupExtensionReturnType(typeof(IEnumerable)]
public class EnumExtension : MarkupExtension
{
public EnumExtension()
{
}
public EnumExtension(Type enumType)
{
this.EnumType = enumType;
}
[ConstructorArgument("enumType")]
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (EnumType == null)
throw new InvalidOperationException("The enum type is not set");
return LocalizationUtilities.GetEnumLocalization(EnumType);
}
}
现在您可以使用它:
SelectedValuePath
是类的Value属性LocalizedValue
。对于DataGrid
XAML 的列来说,是相似的:
多亏了MarkupExtension
😃 ,XAML代码的数量已大大减少(从1行而不是13行)
如果不需要本地化枚举值,则可以将代码简化如下:
[MarkupExtensionReturnType(typeof(IEnumerable))]
public sealed class EnumValuesExtension : MarkupExtension
{
public EnumValuesExtension() { }
public EnumValuesExtension(Type enumType) => EnumType = enumType;
[ConstructorArgument("enumType")]
public Type? EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider) => Enum.GetValues(EnumType);
}
#使用Meziantou.Framework.WPF
您可以使用以下软件包来代替复制以前的Markup扩展Meziantou.Framework.WPF
:
...
...
#其他资源
- Meziantou.Framework.WPF-NuGet
- Meziantou.Framework.WPF-GitHub
- 示例应用程序-GitHub
您对此帖子有任何疑问或建议吗?联络我!