c# - 来自字符串的 IValueConverter

标签 c# wpf binding datatemplate ivalueconverter

我有一个需要在ComboBox 中显示的Enum。我已设法使用 ItemsSource 将枚举值获取到组合框,并且我正在尝试本地化它们。我认为这可以使用值转换器来完成,但由于我的枚举值已经是字符串,编译器会抛出 IValueConverter 无法将字符串作为输入的错误。我不知道有任何其他方法可以将它们转换为其他字符串值。还有其他方法可以做到这一点(不是本地化而是转换)吗?

我正在使用此标记扩展来获取枚举值

[MarkupExtensionReturnType(typeof (IEnumerable))]
public class EnumValuesExtension : MarkupExtension {
    public EnumValuesExtension() {}

    public EnumValuesExtension(Type enumType) {
        this.EnumType = enumType;
    }

    [ConstructorArgument("enumType")]
    public Type EnumType { get; set; }
    public override object ProvideValue(IServiceProvider serviceProvider) {
        if (this.EnumType == null)
            throw new ArgumentException("The enum type is not set");
        return Enum.GetValues(this.EnumType);
    }
}

在 Window.xaml 中

<Converters:UserTypesToStringConverter x:Key="userTypeToStringConverter" />
....
<ComboBox ItemsSource="{Helpers:EnumValuesExtension Data:UserTypes}" 
            Margin="2" Grid.Row="0" Grid.Column="1" SelectedIndex="0" TabIndex="1" IsTabStop="False">
    <ComboBox.ItemTemplate>
        <DataTemplate DataType="{x:Type Data:UserTypes}">
            <Label Content="{Binding Converter=userTypeToStringConverter}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

这是转换器类,它只是一个测试类,还没有本地化。

public class UserTypesToStringConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        return (int) ((Data.UserTypes) value) == 0 ? "Fizička osoba" : "Pravna osoba";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
         return default(Data.UserTypes);
     }
}

-- 编辑--

枚举由 ADO.NET 图生成,无法更改。

最佳答案

是的,当您将值传递到转换器时,它将是一个 string 作为 GetStandardValues 的 Enum (EnumConverter) 的默认类型转换器(即 >Enum.GetValues()) 以字符串形式返回字段的可枚举值。

解决这个问题的最佳方法是编写一个自定义类型转换器来装饰您的枚举。幸运的是,您不是第一个需要这样做的人,请参阅下面的代码示例。

public class EnumTypeConverter : EnumConverter
{
    public EnumTypeConverter()
        : base(typeof(Enum))
    {
    }

    public EnumTypeConverter(Type type)
        : base(type)
    {
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || TypeDescriptor.GetConverter(typeof(Enum)).CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string)
            return GetEnumValue(EnumType, (string)value);

        if (value is Enum)
            return GetEnumDescription((Enum)value);

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (value is Enum && destinationType == typeof(string))
            return GetEnumDescription((Enum)value);

        if (value is string && destinationType == typeof(string))
            return GetEnumDescription(EnumType, (string)value);

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public static bool GetIsEnumBrowsable(Enum value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());
        var attributes = (BrowsableAttribute[])fieldInfo.GetCustomAttributes(typeof(BrowsableAttribute), false);

        return !(attributes.Length > 0) || attributes[0].Browsable;
    }

    public static string GetEnumDescription(Enum value)
    {
        var fieldInfo = value.GetType().GetField(value.ToString());
        var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

        return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
    }

    public static string GetEnumDescription(Type value, string name)
    {
        var fieldInfo = value.GetField(name);
        var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
        return (attributes.Length > 0) ? attributes[0].Description : name;
    }

    public static object GetEnumValue(Type value, string description)
    {
        var fields = value.GetFields();
        foreach (var fieldInfo in fields)
        {
            var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes.Length > 0 && attributes[0].Description == description)
                return fieldInfo.GetValue(fieldInfo.Name);

            if (fieldInfo.Name == description)
                return fieldInfo.GetValue(fieldInfo.Name);
        }

        return description;
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        return base.GetStandardValues(context);
    }

}

使用

[TypeConverter(typeof(EnumTypeConverter))]
public enum UserTypes : int
{
    [Browsable(false)]
    Unkown,    
    [Description("Local")]
    LocalUser,
    [Description("Network")]
    NetworkUser,
    [Description("Restricted")]
    RestrictedUser
} 

正如您所看到的,在上面的枚举中,我们使用了 Description 属性来用用户好友描述来装饰每个字段,并重写了类型转换器以首先查找该属性。

不是 100%,但要让它与您的代码一起使用,您还需要将您的 MarkupExtension 更改为以下内容(注意:我还没有对此进行测试,因此您需要做一些工作是必须的)。

[MarkupExtensionReturnType(typeof (IEnumerable))]
public class EnumValuesExtension : MarkupExtension {

    public EnumValuesExtension() {}

    public EnumValuesExtension(Type enumType) 
    {
        this.EnumType = enumType;
    }

    [ConstructorArgument("enumType")]
    public Type EnumType { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider) 
    {
        if (this.EnumType == null)
            throw new ArgumentException("The enum type is not set");

        var converter = TypeDescriptor.GetConverter(this.EnumType);
        if (converter != null && converter.GetStandardValuesSupported(this.EnumType))        
            return converter.GetStandardValues(this.EnumType);

        return Enum.GetValues(this.EnumType);
    }
}

此外,我只对应用程序进行了有限的本地化,但我相信这是最好且最可维护的方法,因为它将能够利用现有的 .NET 本地化工具(例如卫星程序集)

关于c# - 来自字符串的 IValueConverter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12479409/

相关文章:

c# - 如何给我的 Windows 窗体应用程序换肤?

c# - 如何告诉 Automapper 检查所有源属性是否都有目标属性

C# 在运行时访问对象属性

c# - 有没有办法覆盖列表框中所有项目的颜色?

c# - DockingManager 是否带有用于处理 Anchorables 的内置方法

c# - Margin 和 Padding 是由 ContentControl 实现的吗?

android - 如何将 View 绑定(bind)与包含的 View 一起使用?

wpf - WPF中的自定义日期时间字符串格式

c# - WCF CustomBinding - 无法使用自定义授权策略获取元数据

c# - 执行 SQL 查询时显示进度条