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

Posted

技术标签:

【中文标题】WPF 将 ListBox 绑定到枚举,显示描述属性【英文标题】:WPF Binding a ListBox to an enum, displaying the Description Attribute 【发布时间】:2011-04-28 12:06:15 【问题描述】:

是否可以使用 ObjectDataProvider 方法将 ListBox 绑定到枚举,并以某种方式设置其样式以显示 Description 属性?如果是这样,人们将如何去做...?

【问题讨论】:

***.com/questions/1281490/… 可能重复。 【参考方案1】:

是的,这是可能的。这会做到的。假设我们有枚举

public enum MyEnum

    [Description("MyEnum1 Description")]
    MyEnum1,
    [Description("MyEnum2 Description")]
    MyEnum2,
    [Description("MyEnum3 Description")]
    MyEnum3

那么我们就可以把ObjectDataProvider当作

xmlns:MyEnumerations="clr-namespace:MyEnumerations"
<ObjectDataProvider MethodName="GetValues"
                ObjectType="x:Type sys:Enum"
                x:Key="MyEnumValues">
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="MyEnumerations:MyEnum" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

对于 ListBox,我们将 ItemsSource 设置为 MyEnumValues 并应用带有 Converter 的 ItemTemplate。

<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>

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

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;
    

GetEnumDescription 方法可能应该转到其他地方,但你明白了 :)

检查GetEnumDescription as extension method。

【讨论】:

谢谢,现在就试试看:) 爱它,gank它。我使用了一个小 linq 来配对 GetEnumDescription,你可以在这里找到它pastebin.com/XLm9hbhG 所以你必须为每种类型的枚举做一个转换器? 请注意,您必须创建转换器实例作为资源,例如:&lt;helper:EnumDescriptionConverter x:Key="HEnumDescriptionConverter" /&gt; 如果您在枚举上有不同的属性,这将中断 - 我建议将代码更改为 attrib = attribArray.OfType().FirstOrDefault();并检查 null,因为它更健壮。【参考方案2】:

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

using System.ComponentModel;

namespace EnumDemo

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

        [Description("2")]
        Two,

        Three,
    

使用示例:

<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>

MarkupExtension 实现

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();
        
    

【讨论】:

这比最佳答案要容易得多。我只是有一个问题。当我绑定到存储枚举的属性时,它会正确更新,但在我加载窗口时不会自动显示该值。你知道我该如何解决这个问题吗? @EatATaco 你在使用组合框吗?如果是这样,请看这里:***.com/q/20479976/5612780【参考方案3】:

如果您绑定到 Enum,您可能可以通过 IValueConverter 将其转换为描述。

请参阅Binding ComboBoxes to enums... in Silverlight!,了解如何完成此操作。

更多信息请参见http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx。

【讨论】:

【参考方案4】:

您可以在项目中定义资源文件(*.resx 文件)。在此文件中,您必须定义“键值对”,如下所示:

"YellowCars" : "Yellow Cars",
"RedCars" : "Red Cars",

等等……

键等于您的枚举条目,如下所示:

public enum CarColors

    YellowCars,
    RedCars

等等……

当您使用 WPF 时,您可以在 XAML 代码中实现,如下所示:

<ComboBox ItemsSource="Binding Source=StaticResource CarColors" SelectedValue="Binding CarColor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="Binding Converter=StaticResource CarColorConverter" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

然后你必须写你的转换器,像这样:

using System;
using System.Globalization;
using System.Resources;
using System.Windows.Data;

public class CarColorConverter : IValueConverter

    private static ResourceManager CarColors = new ResourceManager(typeof(Properties.CarColors));

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        var key = ((Enum)value).ToString();
        var result = CarColors.GetString(key);
        if (result == null) 
            result = key;
        

        return result;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        throw new NotImplementedException();
    

我的答案迟到了 7 年 ;-) 但也许它可以被其他人使用!

【讨论】:

【参考方案5】:

是的,可能。

ListBox 可以帮助我们做到这一点,无需转换器。

此方法的步骤如下: 创建一个 ListBox 并将 ListBox 的 ItemsSource 设置为枚举,并将 ListBox 的 SelectedItem 绑定到 selected 属性。

然后将创建每个 ListBoxItem。

第 1 步:定义您的枚举。
public enum EnumValueNames
 
   EnumValueName1, 
   EnumValueName2, 
   EnumValueName3

然后将以下属性添加到您的 DataContext(或 MVVM 的 ViewModel)中,该属性记录被选中的选定项。

public EnumValueNames SelectedEnumValueName  get; set; 
第 2 步:将枚举添加到 Window、UserControl 或 Grid 等的静态资源中。
    <Window.Resources>
        <ObjectDataProvider MethodName="GetValues"
                            ObjectType="x:Type system:Enum"
                            x:Key="EnumValueNames">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="local:EnumValueNames" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
第 3 步:使用列表框填充每个项目
<ListBox ItemsSource="Binding Source=StaticResource EnumValueNames"
              SelectedItem="Binding SelectedEnumValueName, Mode=TwoWay" />

参考资料: https://www.codeproject.com/Articles/130137/Binding-TextBlock-ListBox-RadioButtons-to-Enums

【讨论】:

以上是关于WPF 将 ListBox 绑定到枚举,显示描述属性的主要内容,如果未能解决你的问题,请参考以下文章

WPF 绑定:如何将文件路径列表中的名称绑定到 ListBox 中 TextBlock 的文本?

如何将字符串列表数据绑定到 WPF/WP7 中的 ListBox?

WPF 绑定到资源中的元素

wpf画面ListBox绑定的数据发生变化时 画面闪烁

无法找到来自绑定到 ListBox 的导入命名空间的枚举

双向绑定到 WPF 中多个列表框上的 ListBox SelectedItem