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

时间:2010-10-21 09:11:07

标签: c# wpf data-binding enums listbox

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

5 个答案:

答案 0 :(得分:87)

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

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

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

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方法可能应该去其他地方,但你明白了这一点:)

答案 1 :(得分:2)

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

有关如何完成此操作的说明,请参阅Binding ComboBoxes to enums... in Silverlight!

有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx

答案 2 :(得分: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();
        }
    }
}

答案 3 :(得分:1)

您可以在项目中定义一个资源文件(* .resx文件)。在此文件中,您必须定义&#34;键值对&#34;,如下所示:

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

依旧......

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

public enum CarColors
{
    YellowCars,
    RedCars
}

依旧......

使用WPF时,可以在XAML-Code中实现,如下所示:

<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年到晚;-)但也许它可以被其他人使用!

答案 4 :(得分:0)

是的,可能。

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