15

我正在使用枚举在我的组合框中登记值。我想编写一个转换器来显示所选枚举值的“描述”。And, when selected, it would return the enum value.

大多数在线转换器都没有实现 ConvertBack() 方法(这就是我在这里发布的原因)。

4

5 回答 5

26

这是 ConvertBack 方法:

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    return value;
}

完整的转换器代码:

public class EnumConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) return DependencyProperty.UnsetValue;

        return GetDescription((Enum)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

    public static string GetDescription(Enum en)
    {
        Type type = en.GetType();
        MemberInfo[] memInfo = type.GetMember(en.ToString());
        if (memInfo != null && memInfo.Length > 0)
        {
            object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attrs != null && attrs.Length > 0)
            {
                return ((DescriptionAttribute)attrs[0]).Description;
            }
        }
        return en.ToString();
    }
}

编辑

这是我的组合框 XAML:

<ComboBox ItemsSource="{Binding SampleValues}" 
          SelectedItem="{Binding SelectedValue, Converter={StaticResource enumConverter}}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=., Converter={StaticResource enumConverter}}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
于 2013-11-29T18:15:12.147 回答
10

我知道这是一个老问题,但由于某种原因,这相当复杂,尽管这似乎是一项非常常见的任务(我目前正在 UWP 应用程序上执行此操作)。结合接受的答案、我发现的其他一些项目以及我自己的一些工作,这是我找到的完成这项琐碎任务的最简单方法。简而言之:

  • 通过在 Display 属性中设置描述来定义您的枚举
  • 创建一个将枚举值转换为描述的转换器
  • 在您的视图模型中,公开一组可供选择的枚举值、选定的枚举值,然后初始化那些
  • 定义几个方便的枚举扩展方法
  • 最后,对 ComboBox 进行一些简单的绑定,只需覆盖其 ItemTemplate 即可使用转换器。

枚举

public enum EnumOptions
{
    [Display(Description = "Option 1")]
    OptionOne= 1,
    [Display(Description = "Option 2")]
    OptionTwo,
    [Display(Description = "Option 3")]
    OptionThree
}

转换器

public class EnumToDisplayConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var enumValue = value as Enum;

        return enumValue == null ? DependencyProperty.UnsetValue : enumValue.GetDescriptionFromEnumValue();
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return value;
    }
}

视图模型(部分)

public IReadOnlyList<EnumOptions> Options { get; }

private EnumOptions _selectedOption;

public EnumOptions SelectedOption
{
    get { return _selectedOption; }
    set
    {
        _selectedOption = value;
        OnPropertyChanged(() => SelectedOption);
    }
}

// Initialization in constructor
Options = EnumExtensions.GetValues<EnumOptions>().ToArray();
// If you want to set a default.
SelectedOption = Options[0];

扩展

public static class EnumExtensions
{
    public static string GetDescriptionFromEnumValue(this Enum value)
    {
        var attribute = value.GetType()
            .GetField(value.ToString())
            .GetCustomAttributes(typeof(DisplayAttribute), false)
            .SingleOrDefault() as DisplayAttribute;
        return attribute == null ? value.ToString() : attribute.Description;
    }

    /// <summary>
    /// Enumerates all enum values
    /// </summary>
    /// <typeparam name="T">Enum type</typeparam>
    /// <returns>IEnumerable containing all enum values</returns>
    /// <see cref="http://stackoverflow.com/questions/972307/can-you-loop-through-all-enum-values"/>
    public static IEnumerable<T> GetValues<T>()
    {
        return Enum.GetValues(typeof (T)).Cast<T>();
    }
}

XAML(部分)

<TextBlock Grid.Row="1">Choose an option</TextBlock>
<ComboBox Grid.Row="2"
          ItemsSource="{Binding Options}"
          SelectedItem="{Binding SelectedOption, Mode=TwoWay}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource EnumToDisplayConverter}}"></TextBlock>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
于 2016-05-02T16:25:37.770 回答
2
[ValueConversion(typeof(MyEnum), typeof(String))]
public class MyEnumConverter : IValueConverter
{
    public object Convert(object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        var enumVal = (MyEnum)value;

        // in this example, this is an extension method
        return enumValue.Description();
    }

    public object ConvertBack(object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        var enumDesc = value as string;
        MyEnum val;
        if (Enum.TryParse(typeof(MyEnum), strValue, out val))
        {
            return val;
        }
        return DependencyProperty.UnsetValue;
    }
}

示例中的扩展方法可能如下所示:

public static string Description(this MyEnum enumVal)
{
    // you could use a switch statement here;
    // or maybe a Dictionary
}
于 2013-11-29T17:45:27.417 回答
0

对上述示例的补充以显示使用属性装饰枚举。

sealed class DescriptionAttribute : Attribute
{
    readonly string description;

    public DescriptionAttribute(string description)
    {
        this.description = description;
    }

    public string Description
    {
        get { return description; }
    }
}

enum Vehicle
{
    [Description("Benz")]
    Car,
    [Description("Volvo")]
    Bus,
    [Description("Honda")]
    Bike
}

顺便说一句,我想知道为什么您需要将描述转换回枚举。如果您将枚举本身作为 ItemSource 提供,则可以使用描述技术在 ComboBox 中显示显示值,但是,一旦选择了一个项目,您就可以直接将一个枚举作为选定项目。

于 2013-11-29T19:30:59.650 回答
0

这是我运行良好的示例:

枚举定义:

public enum MyEnum
{
    [Description("Exchange 2007")]
    E2007,
    [Description("Exchange 2010")]
    E2010,
    [Description("Exchange 2013")]
    E2013,
};

助手类:

public static class cHelperClass
{
    #region GetValuesAndDescriptions
    public static object[] GetValuesAndDescriptions(Type enumType)
    {
        var kvPairList = new List<KeyValuePair<string, string>>();

        var listValue = Enum.GetValues(enumType);
        for (var i = 0; i < listValue.Length; i++)
        {
            var value = listValue.GetValue(i);
            var enumValue = (Enum)listValue.GetValue(i);
            kvPairList.Add(new KeyValuePair<string, string>(value.ToString(), GetDescription(enumValue)));
        }

        var valuesAndDescriptions = from kv in kvPairList select new
        {
            Value = kv.Key,
            Description = kv.Value
        };

        return valuesAndDescriptions.ToArray();
    }

    public static string GetDescription(this 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 GetStringValue(this Enum enumItem)
    {
        return enumItem
            .GetType()
            .GetField(enumItem.ToString())
            .GetCustomAttributes<StringValueAttribute>()
            .Select(a => a.Value)
            .FirstOrDefault() ?? enumItem.ToString();
    }

    public static string GetName(Type enumType, object value)
    {
        return Enum.GetName(enumType, value);
    }
    #endregion
}

XAML:

<UserControl.Resources>
    <!-- ObjectDataProvider für WindowStyles -->
    <ObjectDataProvider x:Key="myEnumResource" MethodName="GetValuesAndDescriptions" ObjectType="classes:cHelperClass">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="classes:MyEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</UserControl.Resources>


<ComboBox ItemsSource="{Binding Source={StaticResource myEnumResource}}" DisplayMemberPath="Description" SelectedValuePath="Value" SelectedValue="{Binding MyEnum, Mode=TwoWay}" />
于 2016-02-12T19:41:05.530 回答