WPF将ComboBox绑定到枚举(带有扭曲)

Car*_*rlo 14 data-binding wpf enums combobox

好吧问题是我有这个枚举,但我不希望组合框显示枚举的值.这是枚举:

public enum Mode
    {
        [Description("Display active only")]
        Active,
        [Description("Display selected only")]
        Selected,
        [Description("Display active and selected")]
        ActiveAndSelected
    }
Run Code Online (Sandbox Code Playgroud)

因此,在ComboBox中,而不是显示Active,Selected或ActiveAndSelected,我想为枚举的每个值显示DescriptionProperty.我有一个名为GetDescription()的扩展方法用于枚举:

public static string GetDescription(this Enum enumObj)
        {
            FieldInfo fieldInfo =
                enumObj.GetType().GetField(enumObj.ToString());

            object[] attribArray = fieldInfo.GetCustomAttributes(false);

            if (attribArray.Length == 0)
            {
                return enumObj.ToString();
            }
            else
            {
                DescriptionAttribute attrib =
                    attribArray[0] as DescriptionAttribute;
                return attrib.Description;
            }
        }
Run Code Online (Sandbox Code Playgroud)

那么有没有办法可以将枚举绑定到ComboBox并使用GetDescription扩展方法显示它的内容?

谢谢!

Joe*_*ite 20

我建议使用DataTemplate和ValueConverter.这将允许您自定义它的显示方式,但您仍然可以读取组合框的SelectedItem属性并获取实际的枚举值.

ValueConverters需要很多样板代码,但这里没什么太复杂的.首先,您创建ValueConverter类:

public class ModeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        return ((Mode) value).GetDescription();
    }
    public object ConvertBack(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

由于您只是将枚举值转换为字符串(用于显示),因此您不需要ConvertBack - 这仅适用于双向绑定方案.

然后将ValueConverter的实例放入资源中,如下所示:

<Window ... xmlns:WpfApplication1="clr-namespace:WpfApplication1">
    <Window.Resources>
        <WpfApplication1:ModeConverter x:Key="modeConverter"/>
    </Window.Resources>
    ....
</Window>
Run Code Online (Sandbox Code Playgroud)

然后你准备给ComboBox一个DisplayTemplate,它使用ModeConverter格式化它的项目:

<ComboBox Name="comboBox" ...>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource modeConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
Run Code Online (Sandbox Code Playgroud)

为了测试这个,我也扔了一个Label,这将显示实际的SelectedItem值,它确实显示SelectedItem是枚举而不是显示文本,这是我想要的:

<Label Content="{Binding ElementName=comboBox, Path=SelectedItem}"/>
Run Code Online (Sandbox Code Playgroud)


Mik*_*ley 7

这就是我用MVVM做的事情.在我的模型上,我会定义我的枚举:

    public enum VelocityUnitOfMeasure
    {
        [Description("Miles per Hour")]
        MilesPerHour,
        [Description("Kilometers per Hour")]
        KilometersPerHour
    }
Run Code Online (Sandbox Code Playgroud)

在我的ViewModel上,我公开了一个属性,它提供了可能的选择作为字符串以及一个属性来获取/设置模型的值.如果我们不想在类型中使用每个枚举值,这很有用:

    //UI Helper
    public IEnumerable<string> VelocityUnitOfMeasureSelections
    {
        get
        {
            var units = new []
                            {
                               VelocityUnitOfMeasure.MilesPerHour.Description(),
                               VelocityUnitOfMeasure.KilometersPerHour.Description()
                            };
            return units;
        }
    }

    //VM property
    public VelocityUnitOfMeasure UnitOfMeasure
    {
        get { return model.UnitOfMeasure; }
        set { model.UnitOfMeasure = value; }
    }
Run Code Online (Sandbox Code Playgroud)

此外,我使用通用的EnumDescriptionCoverter:

public class EnumDescriptionConverter : IValueConverter
{
    //From Binding Source
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is Enum)) throw new ArgumentException("Value is not an Enum");
        return (value as Enum).Description();
    }

    //From Binding Target
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is string)) throw new ArgumentException("Value is not a string");
        foreach(var item in Enum.GetValues(targetType))
        {
            var asString = (item as Enum).Description();
            if (asString == (string) value)
            {
                return item;
            }
        }
        throw new ArgumentException("Unable to match string to Enum description");
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,通过视图,我可以执行以下操作:

<Window.Resources>
    <ValueConverters:EnumDescriptionConverter x:Key="enumDescriptionConverter" />
</Window.Resources>
...
<ComboBox SelectedItem="{Binding UnitOfMeasure, Converter={StaticResource enumDescriptionConverter}}"
          ItemsSource="{Binding VelocityUnitOfMeasureSelections, Mode=OneWay}" />
Run Code Online (Sandbox Code Playgroud)


Rob*_*vey 6

我喜欢你思考的方式.但GetCustomAttributes使用反射.这对你的表现有什么影响?

看看这篇文章:WPF - 在ComboBox控件中显示枚举 http://www.infosysblogs.com/microsoft/2008/09/wpf_displaying_enums_in_combob.html

  • 老兄,反射速度并不慢,特别是与显示GUI所需的时间相比.我不认为这是一个问题. (17认同)
  • 但不引用任何个人资料结果.作者对此感到担忧,但这并不意味着它实际上是一个问题. (3认同)