如何在WPF中将枚举设置为ItemsSource

5

如何在XAML中将枚举设置为列表框。但是,在列表框中,我需要显示枚举的描述而不是名称/值。当我单击按钮时,我需要通过icommand将所选枚举作为枚举而不是字符串传递给方法。 例如:

  public enum MyEnum 
  {
     EnumOne = 0,
     [Description("Enum One")]
     EnumTwo = 1,
     [Description("Enum Two")]
     EnumTwo = 2,
     [Description("Enum Three")]
  }

需要将这些枚举绑定到一个带有描述的displaymemberpath的列表框中。然后,在列表框中进行选择后,将所选的枚举传递进去,就像这样:
  private void ButtonDidClick(MyEnum enum)
  {

  }

XAML:

  <ListBox ItemsSource="{Binding MyEnum"} /> ?

我知道如何将命令与按钮连接起来,等等。对于任何帮助,谢谢。


我使用将其转换为Dictionary<enum,string>,并使用Value作为DisplayMember。 - paparazzo
1
我认为这个答案可以满足你的需求:https://dev59.com/wmbWa4cB1Zd3GeqPSQA7 - sa_ddam213
那是一个不错的例子。谢谢。 - TMan
3个回答

6

使用 ObjectDataProvider:

<ObjectDataProvider x:Key="enumValues"
   MethodName="GetValues" ObjectType="{x:Type System:Enum}">
      <ObjectDataProvider.MethodParameters>
           <x:Type TypeName="local:ExampleEnum"/>
      </ObjectDataProvider.MethodParameters>
 </ObjectDataProvider>

然后绑定到静态资源:

ItemsSource="{Binding Source={StaticResource enumValues}}"

在这里找到了解决方案这里


5

来自生产应用程序
我之前在 Stack Overflow 上找到了这个代码,但无法找到来源
将 DisplayMemberPath 绑定到 Value

public static Dictionary<T, string> EnumToDictionary<T>()
    where T : struct
{
    Type enumType = typeof(T);

    // Can't use generic type constraints on value types,
    // so have to do check like this
    if (enumType.BaseType != typeof(Enum))
        throw new ArgumentException("T must be of type System.Enum");
    Dictionary<T, string> enumDL = new Dictionary<T, string>();
    foreach (T val in Enum.GetValues(enumType))
    {
        enumDL.Add(val, val.ToString());
    }
    return enumDL;
}

GetDescription方法

对于想了解如何读取描述属性值的人。以下内容可以轻松地转换为使用枚举或扩展。我发现这种实现更加灵活。

使用此方法,将val.ToString()替换为GetDescription(val)

    /// <summary>
    /// Returns the value of the 'Description' attribute; otherwise, returns null.
    /// </summary>
    public static string GetDescription(object value)
    {
        string sResult = null;

        FieldInfo oFieldInfo = value.GetType().GetField(value.ToString());

        if (oFieldInfo != null)
        {
            object[] oCustomAttributes = oFieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);

            if ((oCustomAttributes != null) && (oCustomAttributes.Length > 0))
            {
                sResult = ((DescriptionAttribute)oCustomAttributes[0]).Description;
            }
        }
        return sResult;
    }

非常好,运行得很顺利。但是我需要字典中的值是枚举的描述而不是值,所以我之前写了一个GetDescription(this enum value)函数来返回描述,所以我只需在enumDL.Add()中调用该函数并将值作为枚举传递即可。非常好用,感谢您的帮助。 - TMan

1
您可以通过将枚举转换为MyEnum-字符串元组列表,并使用ListBox的DisplayMemberPath参数来显示描述项来实现此操作。当您选择特定的元组时,只需获取其中的MyEnum部分,并将其用于在ViewModel中设置SelectedEnumValue属性。
这是代码:
XAML:
<Window x:Class="EnumToListBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ListBox Grid.Row="0" 
             ItemsSource="{Binding EnumToDescriptions}"
             SelectedItem="{Binding SelectedEnumToDescription}"
             DisplayMemberPath="Item2"/>
    <TextBlock Grid.Row="1" 
               Text="{Binding SelectedEnumToDescription.Item2}"/>
</Grid>

代码后端:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }
}

public class ViewModel : PropertyChangedNotifier
{
    private List<Tuple<MyEnum, string>> _enumToDescriptions = new List<Tuple<MyEnum, string>>();
    private Tuple<MyEnum, string> _selectedEnumToDescription;

    public ViewModel()
    {
        Array Values = Enum.GetValues(typeof(MyEnum));
        foreach (var Value in Values)
        {
            var attributes = Value.GetType().GetField(Value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
            var attribute = attributes[0] as DescriptionAttribute;
            _enumToDescriptions.Add(new Tuple<MyEnum, string>((MyEnum)Value, (string)attribute.Description));
        }
    }

    public List<Tuple<MyEnum, string>> EnumToDescriptions
    {
        get
        {
            return _enumToDescriptions;
        }
        set
        {
            _enumToDescriptions = value;
            OnPropertyChanged("EnumToDescriptions");
        }
    }

    public Tuple<MyEnum, string> SelectedEnumToDescription
    {
        get
        {
            return _selectedEnumToDescription;
        }
        set
        {
            _selectedEnumToDescription = value;
            SelectedEnumValue = _selectedEnumToDescription.Item1;
            OnPropertyChanged("SelectedEnumToDescription");
        }
    }

    private MyEnum? _selectedEnumValue;
    public MyEnum? SelectedEnumValue
    {
        get
        {
            return _selectedEnumValue;
        }
        set
        {
            _selectedEnumValue = value;
            OnPropertyChanged("SelectedEnumValue");
        }
    }
}

public enum MyEnum
{
    [Description("Item1Description")]
    Item1,
    [Description("Item2Description")]
    Item2,
    [Description("Item3Description")]
    Item3,
    [Description("Item4Description")]
    Item4
}

public class PropertyChangedNotifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

刚看到您需要的是描述而不是名称 - 我会稍微修改一下我的代码,以更好地回答您的问题。 - Andrew
为什么你会使用元组而不是字典呢? - paparazzo
你可以用任何一种方式实现 - 通常我会将元组包装起来,以便暴露更具描述性的属性名称,而不是在字典中使用 'Item1' 和 'Item2' 或 'Key.Name' 和 'Value'。这样绑定就更加明显,无需查看 ViewModel 代码。 - Andrew
是的,如果不必要的话,我不太喜欢元组。不过还是感谢你的回复。 - TMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接