gre*_*b64 6 .net c# enums datagridview typeconverter
我有以下场景:我有一个枚举,并希望绑定它在DataGridViewTextBoxColumn上的DataGridView(数据绑定)中显示它.
这是我的枚举:
//[TypeConverter(typeof(EnumStringConverter))]
public enum YesNoNA
{
[EnumDescription("Yes")]
Yes,
[EnumDescription("No")]
No,
[EnumDescription("N/A")]
NA
}
Run Code Online (Sandbox Code Playgroud)
这是一个使用它的简单属性:
[TypeConverter(typeof(EnumStringConverter))]
public YesNoNA HighLimitWithinBounds { get; protected set; }
Run Code Online (Sandbox Code Playgroud)
在我上面的情况下,typeconverter工作正常.它为我做了转换.
但是,这比我理想的解决方案更复杂.如果我将typeconverter放在Enum本身(取消注释上面的代码),并在属性上注释掉typeconverter,则不再调用typeconverter!
我已经在其他类上完成了这个约定,它运行得很好.
为什么直接在枚举上放置一个typeconverter不起作用?
作为参考,这是我的typeconverter:
public class EnumStringConverter : TypeConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType)
{
if (value != null && destinationType == typeof(string))
{
return "Edited to protect the innocent!";
}
return TypeDescriptor.GetConverter(typeof(Enum)).ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
};
Run Code Online (Sandbox Code Playgroud)
我不确定你所说的“这比我的理想解决方案更复杂”是什么意思。我有一种与你不同的方法,但它可能不会那么复杂。我想说,我的方法前期涉及更多开销,但随着您在应用程序中使用它的次数越来越多,它会得到回报。它使您的应用程序准备好可本地化,并且意味着您不必向每个枚举值添加属性。
1)创建资源管理器缓存
这部分是可选的;但是,如果您像我一样多次使用多个资源文件,则可以通过减少反射次数来提高性能。
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Resources;
namespace AppResourceLib.Public.Reflection
{
internal static class ResourceManagerCache
{
private static Dictionary<Type, ResourceManager> _resourceManagerMap =
new Dictionary<Type, ResourceManager>();
public static ResourceManager GetResourceManager(Type resourceType)
{
ResourceManager resourceManager = null;
// Make sure the type is valid.
if (null != resourceType)
{
// Try getting the cached resource manager.
if (!ResourceManagerCache._resourceManagerMap.TryGetValue(resourceType, out resourceManager))
{
// If it is not in the cache create it.
resourceManager = resourceType.InvokeMember(
"ResourceManager",
(BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic),
null,
null,
null) as ResourceManager;
// If it was created, add the resource manager to the cache.
if (null != resourceManager)
{
ResourceManagerCache._resourceManagerMap.Add(resourceType, resourceManager);
}
}
}
return resourceManager;
}
}
}
Run Code Online (Sandbox Code Playgroud)
2) 创建本地化描述属性
这是您将应用于 Enum 类型的属性。最酷的一点是,您不必向每个枚举添加属性,只需在枚举类型声明上方添加一次即可。
using System;
using System.ComponentModel;
namespace AppResourceLib.Public.Reflection
{
/// <summary>
/// A resource type attribute that can be applied to enumerations.
/// </summary>
[AttributeUsage(AttributeTargets.Enum)]
public sealed class LocalizedDescriptionAttribute : Attribute
{
/// <summary>
/// The type of resource associated with the enum type.
/// </summary>
private Type _resourceType;
public LocalizedDescriptionAttribute(Type resourceType)
{
this._resourceType = resourceType;
}
/// <summary>
/// The type of resource associated with the enum type.
/// </summary>
public Type ResourceType
{
get
{
return this._resourceType;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
3) 创建本地化描述转换器
这会将枚举值转换为您将在字符串资源 (.resx) 文件中提供的字符串。
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Windows.Data;
namespace AppResourceLib.Public.Reflection
{
[ValueConversion(typeof(Object), typeof(String))]
public class LocalizedDescriptionConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object param, CultureInfo cultureInfo)
{
String description = null;
if (null != value)
{
// If everything fails then at least return the value.ToString().
description = value.ToString();
// Get the LocalizedDescriptionAttribute of the object.
LocalizedDescriptionAttribute attribute =
value.GetType().GetCustomAttribute(typeof(LocalizedDescriptionAttribute))
as LocalizedDescriptionAttribute;
// Make sure we found a LocalizedDescriptionAttribute.
if (null != attribute)
{
ResourceManager resourceManager =
ResourceManagerCache.GetResourceManager(attribute.ResourceType);
if (null != resourceManager)
{
// Use the ResourceManager to get the description you gave the object value.
// Here we just use the object value.ToString() (the name of the object) to get
// the string in the .resx file. The only constraint here is that you have to
// name your object description strings in the .resx file the same as your objects.
// The benefit is that you only have to declare the LocalizedDescriptionAttribute
// above the object type, not an attribute over every object.
// And this way is localizable.
description = resourceManager.GetString(value.ToString(), cultureInfo);
String formatString = (param as String);
// If a format string was passed in as a parameter,
// make a string out of that.
if (!String.IsNullOrEmpty(formatString))
{
formatString = formatString.Replace("\\t", "\t");
formatString = formatString.Replace("\\n", "\n");
formatString = formatString.Replace("\\r", "\r");
description = String.Format(formatString, value.ToString(), description);
}
}
}
}
return description;
}
public Object ConvertBack(Object value, Type targetType, Object param, CultureInfo cultureInfo)
{
throw new NotImplementedException();
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
4)创建资源(.resx)字符串文件
现在您想要创建一个资源文件,其中包含您想要的枚举键值样式的描述。我的意思是,在字符串资源的“名称”列中,您将放置各个枚举的确切名称,而在“值”列中,您将放置转换该枚举时想要获取的字符串。
例如,假设您有以下枚举。
public enum MyColors
{
Black,
Blue,
White
}
Run Code Online (Sandbox Code Playgroud)
那么你的字符串资源文件将如下所示......
名称 | 价值
黑色| 深
蓝色| 冷色
白色 | 明亮的颜色
5) 创建带有属性的枚举
现在我们终于用 LocalizedDescription 进行 Enum 声明。传递到 LocalizedDescription 属性的参数是字符串资源文件的类型。现在,当使用转换器时,它将查看枚举类型的属性,获取资源文件,查找与特定枚举值的字符串值匹配的键字符串,并将资源文件中的值作为转换后的字符串返回。
using AppResourceLib.Public;
using AppResourceLib.Public.Reflection;
namespace MyEnums
{
[LocalizedDescription(typeof(MyColorStrings))]
public enum MyColors
{
Black,
Blue,
White
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法的主要缺点是,只有当资源文件中的“Name”键与枚举值的名称匹配时,它才有效。这是在资源文件中引用字符串值而不为每个枚举提供描述属性的唯一方法。那么如何使用它来显示值呢?这是一个例子...
在您的 xaml 代码中,您需要创建一个数据提供程序来获取 UI 元素的枚举值(我在这里使用 ComboBox...)。然后,您需要使转换器可用并模板化您的 UI 元素以使用枚举转换器。所以就这样...
<!-- Enum Colors -->
<ObjectDataProvider x:Key="MyColorEnums"
MethodName="GetValues"
ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="MyColors"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<!-- Enum Type Converter -->
<LocalizedDescriptionConverter x:Key="EnumConverter"/>
<!-- Dropdown Expand ComboBox Template -->
<DataTemplate x:Key="MyColorsComboBoxTemplate">
<Label Content="{Binding Path=., Mode=OneWay,
Converter={StaticResource EnumConverter}}"
Height="Auto" Margin="0" VerticalAlignment="Center"/>
</DataTemplate>
<!-- And finally the ComboBox that will display all of your enum values
but will use the strings from the resource file instead of enum.ToString() -->
<ComboBox Width="80" HorizontalAlignment="Left"
ItemTemplate="{StaticResource MyColorsComboBoxTemplate}"
ItemsSource="{Binding Source={StaticResource MyColorEnums}}">
Run Code Online (Sandbox Code Playgroud)
哇,抱歉,这么长。我不确定这对您来说是否太复杂,但这是另一种选择。希望能帮助到你!