WPF将ListBox绑定到枚举,显示描述属性

Mic*_*han 35 c# data-binding wpf enums listbox

是否可以使用ObjectDataProvider方法将ListBox绑定到枚举,并以某种方式设置样式以显示描述attriibute?如果是这样,怎么会这样做...?

Fre*_*lad 91

对的,这是可能的.这样做.说我们有枚举

public enum MyEnum
{
    [Description("MyEnum1 Description")]
    MyEnum1,
    [Description("MyEnum2 Description")]
    MyEnum2,
    [Description("MyEnum3 Description")]
    MyEnum3
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用ObjectDataProvider

xmlns:MyEnumerations="clr-namespace:MyEnumerations"
Run Code Online (Sandbox Code Playgroud)
<ObjectDataProvider MethodName="GetValues"
                ObjectType="{x:Type sys:Enum}"
                x:Key="MyEnumValues">
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="MyEnumerations:MyEnum" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
Run Code Online (Sandbox Code Playgroud)

对于ListBox,我们将ItemsSource设置为MyEnumValues并将ItemTemplate应用于Converter.

<ListBox Name="c_myListBox" SelectedIndex="0" Margin="8"
        ItemsSource="{Binding Source={StaticResource MyEnumValues}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

在转换器中,我们得到描述并返回它

public class EnumDescriptionConverter : IValueConverter
{
    private string GetEnumDescription(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;
        }
    }

    object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Enum myEnum = (Enum)value;
        string description = GetEnumDescription(myEnum);
        return description;
    }

    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.Empty;
    }
}
Run Code Online (Sandbox Code Playgroud)

GetEnumDescription方法可能应该去别的地方,但你明白了:)

  • 如果您对我最好建议修改的代码属性= attribArray.OfType <DescriptionAttribute>()的enum-不同的属性,这将破坏FirstOrDefault(); 并检查null,因为它更健壮. (10认同)
  • 请注意,您必须创建转换器的实例作为ressource,例如:`<helper:EnumDescriptionConverter x:Key ="HEnumDescriptionConverter"/>` (7认同)
  • 喜欢它,咬了它.我使用了一个小的linq配对GetEnumDescription,你可以在这里抓住它http://pastebin.com/XLm9hbhG (4认同)
  • 那么你必须为每种类型的枚举制作转换器吗? (2认同)

chv*_*lav 8

另一个解决方案是自定义MarkupExtension,它从枚举类型生成项目。这使得 xaml 更加紧凑和可读。

using System.ComponentModel;

namespace EnumDemo
{
    public enum Numbers
    {
        [Description("1")]
        One,

        [Description("2")]
        Two,

        Three,
    }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

<Window x:Class="EnumDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:EnumDemo">

    <ListBox ItemsSource="{local:EnumToCollection EnumType={x:Type local:Numbers}}"/>

</Window>
Run Code Online (Sandbox Code Playgroud)

标记扩展实现

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Markup;

namespace EnumDemo
{
    public class EnumToCollectionExtension : MarkupExtension
    {
        public Type EnumType { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (EnumType == null) throw new ArgumentNullException(nameof(EnumType));

            return Enum.GetValues(EnumType).Cast<Enum>().Select(EnumToDescriptionOrString);
        }

        private string EnumToDescriptionOrString(Enum value)
        {
            return value.GetType().GetField(value.ToString())
                       .GetCustomAttributes(typeof(DescriptionAttribute), false)
                       .Cast<DescriptionAttribute>()
                       .FirstOrDefault()?.Description ?? value.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)