将枚举属性数据绑定到 WPF 中的组合框

Posted

技术标签:

【中文标题】将枚举属性数据绑定到 WPF 中的组合框【英文标题】:Databinding an enum property to a ComboBox in WPF 【发布时间】:2010-09-08 16:39:57 【问题描述】:

以如下代码为例:

public enum ExampleEnum  FooBar, BarFoo 

public class ExampleClass : INotifyPropertyChanged

    private ExampleEnum example;

    public ExampleEnum ExampleProperty 
     get  return example;   /* set and notify */;  

我希望将属性 ExampleProperty 数据绑定到 ComboBox,以便它显示选项“FooBar”和“BarFoo”并在 TwoWay 模式下工作。理想情况下,我希望我的 ComboBox 定义看起来像这样:

<ComboBox ItemsSource="What goes here?" SelectedItem="Binding Path=ExampleProperty" />

目前我在我的窗口中安装了 ComboBox.SelectionChanged 和 ExampleClass.PropertyChanged 事件的处理程序,我在其中手动进行绑定。

有更好的或某种规范的方法吗?您通常会使用转换器吗?如何使用正确的值填充 ComboBox?我现在什至不想开始使用 i18n。

编辑

所以回答了一个问题:如何使用正确的值填充 ComboBox。

从静态 Enum.GetValues 方法中通过 ObjectDataProvider 将枚举值作为字符串列表检索:

<Window.Resources>
    <ObjectDataProvider MethodName="GetValues"
        ObjectType="x:Type sys:Enum"
        x:Key="ExampleEnumValues">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="ExampleEnum" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

这可以用作我的 ComboBox 的 ItemsSource:

<ComboBox ItemsSource="Binding Source=StaticResource ExampleEnumValues"/>

【问题讨论】:

我对此进行了探索,并提供了一个您可以在位于 here 的 WPF 中使用(完成本地化)的解决方案。 【参考方案1】:

您可以创建自定义标记扩展。

使用示例:

enum Status

    [Description("Available.")]
    Available,
    [Description("Not here right now.")]
    Away,
    [Description("I don't have time right now.")]
    Busy

在 XAML 的顶部:

    xmlns:my="clr-namespace:namespace_to_enumeration_extension_class

然后……

<ComboBox 
    ItemsSource="Binding Source=my:Enumeration x:Type my:Status" 
    DisplayMemberPath="Description" 
    SelectedValue="Binding CurrentStatus"  
    SelectedValuePath="Value"  /> 

以及实现...

public class EnumerationExtension : MarkupExtension
  
    private Type _enumType;


    public EnumerationExtension(Type enumType)
    
      if (enumType == null)
        throw new ArgumentNullException("enumType");

      EnumType = enumType;
    

    public Type EnumType
    
      get  return _enumType; 
      private set
      
        if (_enumType == value)
          return;

        var enumType = Nullable.GetUnderlyingType(value) ?? value;

        if (enumType.IsEnum == false)
          throw new ArgumentException("Type must be an Enum.");

        _enumType = value;
      
    

    public override object ProvideValue(IServiceProvider serviceProvider)
    
      var enumValues = Enum.GetValues(EnumType);

      return (
        from object enumValue in enumValues
        select new EnumerationMember
          Value = enumValue,
          Description = GetDescription(enumValue)
        ).ToArray();
    

    private string GetDescription(object enumValue)
    
      var descriptionAttribute = EnumType
        .GetField(enumValue.ToString())
        .GetCustomAttributes(typeof (DescriptionAttribute), false)
        .FirstOrDefault() as DescriptionAttribute;


      return descriptionAttribute != null
        ? descriptionAttribute.Description
        : enumValue.ToString();
    

    public class EnumerationMember
    
      public string Description  get; set; 
      public object Value  get; set; 
    
  

【讨论】:

@Gregor S. my:Enumeration 是什么? @Crown 'my' 是您在 xaml 文件顶部声明的命名空间前缀:例如 xmlns:my="clr-namespace:namespace_to_enumeration_extension_class。枚举是 EnumerationExtension 的缩写,在 xaml 中您不需要必须写出整个扩展类名。 +1,但是 WPF 完成最简单的事情所需的代码量确实令人头晕 我不太喜欢它让您在视图中使用对模型的一部分(枚举类型)的引用的方式,在 ItemsSource 参数中。为了保持视图和模型解耦,我需要在 ViewModel 中创建枚举的副本并编写 ViewModel 代码以在两者之间进行转换……这将使解决方案不再那么简单。或者有没有办法从 ViewModel 提供类型本身? 另一个限制是,如果您有多种语言,则不能这样做。【参考方案2】:

在视图模型中你可以拥有:

public MyEnumType SelectedMyEnumType 

    get  return _selectedMyEnumType; 
    set  
            _selectedMyEnumType = value;
            OnPropertyChanged("SelectedMyEnumType");
        


public IEnumerable<MyEnumType> MyEnumTypeValues

    get
    
        return Enum.GetValues(typeof(MyEnumType))
            .Cast<MyEnumType>();
    

在 XAML 中,ItemSource 绑定到 MyEnumTypeValuesSelectedItem 绑定到 SelectedMyEnumType

<ComboBox SelectedItem="Binding SelectedMyEnumType" ItemsSource="Binding MyEnumTypeValues"></ComboBox>

【讨论】:

这在我的 Universal 应用程序中运行得非常好,而且很容易实现。谢谢! 这非常有效,并且需要的代码要少得多。【参考方案3】:

我不喜欢在 UI 中使用枚举的名称。我更喜欢为用户使用不同的值(DisplayMemberPath)和不同的值(在这种情况下为枚举)(SelectedValuePath)。这两个值可以打包到KeyValuePair 并存储在字典中。

XAML

<ComboBox Name="fooBarComboBox" 
          ItemsSource="Binding Path=ExampleEnumsWithCaptions" 
          DisplayMemberPath="Value" 
          SelectedValuePath="Key"
          SelectedValue="Binding Path=ExampleProperty, Mode=TwoWay" > 

C#

public Dictionary<ExampleEnum, string> ExampleEnumsWithCaptions  get;  =
    new Dictionary<ExampleEnum, string>()
    
        ExampleEnum.FooBar, "Foo Bar",
        ExampleEnum.BarFoo, "Reversed Foo Bar",
        //ExampleEnum.None, "Hidden in UI",
    ;


private ExampleEnum example;
public ExampleEnum ExampleProperty

    get  return example; 
    set  /* set and notify */; 

编辑:与 MVVM 模式兼容。

【讨论】:

我认为您的回答被低估了,考虑到 ComboBox 本身的期望,这似乎是最好的选择。或许您可以使用Enum.GetValues 在getter 中放置一个字典构建器,但这并不能解决要显示的名称部分。最后,特别是如果实现了 I18n,无论如何,如果枚举发生更改,您将不得不手动更改内容。但是枚举不应该经常改变,如果有的话,是吗? +1 这个答案很棒,它允许本地化枚举描述......谢谢! 这个解决方案非常好,因为它处理枚举和本地化的代码比其他解决方案少! Dictionary 的问题在于键是按哈希值排序的,因此几乎无法控制。虽然有点冗长,但我使用 List> 代替。好主意。 @CoperNick @Pragmateek 新修复:public Dictionary&lt;ExampleEnum, string&gt; ExampleEnumsWithCaptions get; = new Dictionary&lt;ExampleEnum, string&gt;() ExampleEnum.FooBar, "Foo Bar", ExampleEnum.BarFoo, "Reversed Foo Bar", //ExampleEnum.None, "Hidden in UI", ;【参考方案4】:

我不知道在 XAML-only 中是否可行,但请尝试以下方法:

为您的 ComboBox 命名,以便您可以在代码隐藏中访问它:“typesComboBox1”

现在试试下面的

typesComboBox1.ItemsSource = Enum.GetValues(typeof(ExampleEnum));

【讨论】:

【参考方案5】:

使用 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"

找到这个solution at this blog

【讨论】:

不错的答案。顺便说一句,它使您不必担心枚举到字符串问题的Converter 链接解决方案似乎已死(韩文还是日文?)。如果我将您的代码放到我的 XAML 资源中,它会说 WPF 项目中不支持 Enum。 你需要在Window标签xlmns定义中添加'xmlns:System="clr-namespace:System;assembly=mscorlib"' 简单优雅的解决方案,这个需要提升!【参考方案6】:

根据ageektrapped 提供的已接受但现已删除的答案,我创建了一个精简版,但没有一些更高级的功能。所有代码都包含在此处,以允许您复制粘贴它而不会被链接腐烂阻止。

我使用System.ComponentModel.DescriptionAttribute,它真正用于设计时描述。如果您不喜欢使用此属性,您可以创建自己的属性,但我认为使用此属性确实可以完成工作。如果您不使用该属性,则名称将默认为代码中枚举值的名称。

public enum ExampleEnum 

  [Description("Foo Bar")]
  FooBar,

  [Description("Bar Foo")]
  BarFoo


这里是用作物品来源的类:

public class EnumItemsSource : Collection<String>, IValueConverter 

  Type type;

  IDictionary<Object, Object> valueToNameMap;

  IDictionary<Object, Object> nameToValueMap;

  public Type Type 
    get  return this.type; 
    set 
      if (!value.IsEnum)
        throw new ArgumentException("Type is not an enum.", "value");
      this.type = value;
      Initialize();
    
  

  public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) 
    return this.valueToNameMap[value];
  

  public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture) 
    return this.nameToValueMap[value];
  

  void Initialize() 
    this.valueToNameMap = this.type
      .GetFields(BindingFlags.Static | BindingFlags.Public)
      .ToDictionary(fi => fi.GetValue(null), GetDescription);
    this.nameToValueMap = this.valueToNameMap
      .ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
    Clear();
    foreach (String name in this.nameToValueMap.Keys)
      Add(name);
  

  static Object GetDescription(FieldInfo fieldInfo) 
    var descriptionAttribute =
      (DescriptionAttribute) Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute));
    return descriptionAttribute != null ? descriptionAttribute.Description : fieldInfo.Name;
  


您可以像这样在 XAML 中使用它:

<Windows.Resources>
  <local:EnumItemsSource
    x:Key="ExampleEnumItemsSource"
    Type="x:Type local:ExampleEnum"/>
</Windows.Resources>
<ComboBox
  ItemsSource="StaticResource ExampleEnumItemsSource"
  SelectedValue="Binding ExampleProperty, Converter=StaticResource ExampleEnumItemsSource"/> 

【讨论】:

【参考方案7】:

我最喜欢的方法是使用ValueConverter,以便 ItemsSource 和 SelectedValue 都绑定到同一个属性。这需要不需要额外的属性来保持您的 ViewModel 干净整洁。

<ComboBox ItemsSource="Binding Path=ExampleProperty, Converter=x:EnumToCollectionConverter, Mode=OneTime"
          SelectedValuePath="Value"
          DisplayMemberPath="Description"
          SelectedValue="Binding Path=ExampleProperty" />

以及Converter的定义:

public static class EnumHelper

  public static string Description(this Enum e)
  
    return (e.GetType()
             .GetField(e.ToString())
             .GetCustomAttributes(typeof(DescriptionAttribute), false)
             .FirstOrDefault() as DescriptionAttribute)?.Description ?? e.ToString();
  


[ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter

  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  
    return Enum.GetValues(value.GetType())
               .Cast<Enum>()
               .Select(e => new ValueDescription()  Value = e, Description = e.Description())
               .ToList();
  
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  
    return null;
  
  public override object ProvideValue(IServiceProvider serviceProvider)
  
    return this;
  

此转换器适用于任何枚举。 ValueDescription 只是一个具有Value 属性和Description 属性的简单类。您可以轻松地将TupleItem1Item2 一起使用,或者将KeyValuePairKeyValue 一起使用,而不是Value 和Description 或您选择的任何其他类,只要它可以保存枚举值和该枚举值的字符串描述。

【讨论】:

不错的答案!对于ValueDescription 类,如果不需要,可以省略Description 属性。一个只有 Value 属性的简单类也可以工作! 另外,如果要绑定到 RadioButton,则 Convert 方法必须返回字符串列表,即 .Select(e =&gt; e.ToString()),而不是使用 ValueDescription 类。 也可以使用KeyValuePair 代替ValueDescription,例如shown here【参考方案8】:

你可以考虑这样的事情:

    定义文本块的样式,或者您想用来显示枚举的任何其他控件:

    <Style x:Key="enumStyle" TargetType="x:Type TextBlock">
        <Setter Property="Text" Value="&lt;NULL&gt;"/>
        <Style.Triggers>
            <Trigger Property="Tag">
                <Trigger.Value>
                    <proj:YourEnum>Value1<proj:YourEnum>
                </Trigger.Value>
                <Setter Property="Text" Value="DynamicResource yourFriendlyValue1"/>
            </Trigger>
            <!-- add more triggers here to reflect your enum -->
        </Style.Triggers>
    </Style>
    

    定义 ComboBoxItem 的样式

    <Style TargetType="x:Type ComboBoxItem">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <TextBlock Tag="Binding" Style="StaticResource enumStyle"/>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    添加一个组合框并使用您的枚举值加载它:

    <ComboBox SelectedValue="Binding Path=your property goes here" SelectedValuePath="Content">
        <ComboBox.Items>
            <ComboBoxItem>
                <proj:YourEnum>Value1</proj:YourEnum>
            </ComboBoxItem>
        </ComboBox.Items>
    </ComboBox>
    

如果你的枚举很大,你当然可以在代码中做同样的事情,节省大量的输入。 我喜欢这种方法,因为它使本地化变得容易 - 你定义所有模板一次,然后,你只更新你的字符串资源文件。

【讨论】:

SelectedValuePath="Content" 在这里帮助了我。我将我的 ComboBoxItems 作为字符串值,并且一直无法将 ComboBoxItem 转换为我的枚举类型。谢谢【参考方案9】:

这是一个使用辅助方法的通用解决方案。 这也可以处理任何底层类型的枚举(byte、sbyte、uint、long 等)

辅助方法:

static IEnumerable<object> GetEnum<T>() 
    var type    = typeof(T);
    var names   = Enum.GetNames(type);
    var values  = Enum.GetValues(type);
    var pairs   =
        Enumerable.Range(0, names.Length)
        .Select(i => new 
                Name    = names.GetValue(i)
            ,   Value   = values.GetValue(i) )
        .OrderBy(pair => pair.Name);
    return pairs;
//method

查看模型:

public IEnumerable<object> EnumSearchTypes 
    get 
        return GetEnum<SearchTypes>();
    
//property

组合框:

<ComboBox
    SelectedValue       ="Binding SearchType"
    ItemsSource         ="Binding EnumSearchTypes"
    DisplayMemberPath   ="Name"
    SelectedValuePath   ="Value"
/>

【讨论】:

【参考方案10】:

如果您使用的是 MVVM,根据@rudigrobler 的回答,您可以执行以下操作:

将以下属性添加到 ViewModel

public Array ExampleEnumValues => Enum.GetValues(typeof(ExampleEnum));

然后在 XAML 中执行以下操作:

<ComboBox ItemsSource="Binding ExampleEnumValues" ... />

【讨论】:

【参考方案11】:

这是一个 DevExpress 的特定答案,基于 Gregor S. 的最高投票答案(目前有 128 票)。

这意味着我们可以在整个应用程序中保持样式一致:

不幸的是,未经修改,原始答案不适用于来自 DevExpress 的ComboBoxEdit

首先,ComboBoxEdit 的 XAML:

<dxe:ComboBoxEdit ItemsSource="Binding Source=xamlExtensions:XamlExtensionEnumDropdown x:myEnum:EnumFilter"
    SelectedItem="Binding BrokerOrderBookingFilterSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged"
    DisplayMember="Description"
    MinWidth="144" Margin="5" 
    HorizontalAlignment="Left"
    IsTextEditable="False"
    ValidateOnTextInput="False"
    AutoComplete="False"
    IncrementalFiltering="True"
    FilterCondition="Like"
    ImmediatePopup="True"/>

不用说,您需要将 xamlExtensions 指向包含 XAML 扩展类(定义如下)的命名空间:

xmlns:xamlExtensions="clr-namespace:XamlExtensions"

我们必须将myEnum 指向包含枚举的命名空间:

xmlns:myEnum="clr-namespace:MyNamespace"

然后,枚举:

namespace MyNamespace

    public enum EnumFilter
    
        [Description("Free as a bird")]
        Free = 0,

        [Description("I'm Somewhat Busy")]
        SomewhatBusy = 1,

        [Description("I'm Really Busy")]
        ReallyBusy = 2
    

XAML 的问题是我们不能使用 SelectedItemValue,因为这会引发错误,因为 setter 无法访问(您的疏忽,DevExpress)。所以我们要修改我们的ViewModel,直接从对象中获取值:

private EnumFilter _filterSelected = EnumFilter.All;
public object FilterSelected

    get
    
        return (EnumFilter)_filterSelected;
    
    set
    
        var x = (XamlExtensionEnumDropdown.EnumerationMember)value;
        if (x != null)
        
            _filterSelected = (EnumFilter)x.Value;
        
        OnPropertyChanged("FilterSelected");
    

为了完整起见,这里是原始答案中的 XAML 扩展(稍微重命名):

namespace XamlExtensions

    /// <summary>
    ///     Intent: XAML markup extension to add support for enums into any dropdown box, see http://bit.ly/1g70oJy. We can name the items in the
    ///     dropdown box by using the [Description] attribute on the enum values.
    /// </summary>
    public class XamlExtensionEnumDropdown : MarkupExtension
    
        private Type _enumType;


        public XamlExtensionEnumDropdown(Type enumType)
        
            if (enumType == null)
            
                throw new ArgumentNullException("enumType");
            

            EnumType = enumType;
        

        public Type EnumType
        
            get  return _enumType; 
            private set
            
                if (_enumType == value)
                
                    return;
                

                var enumType = Nullable.GetUnderlyingType(value) ?? value;

                if (enumType.IsEnum == false)
                
                    throw new ArgumentException("Type must be an Enum.");
                

                _enumType = value;
            
        

        public override object ProvideValue(IServiceProvider serviceProvider)
        
            var enumValues = Enum.GetValues(EnumType);

            return (
                from object enumValue in enumValues
                select new EnumerationMember
                       
                           Value = enumValue,
                           Description = GetDescription(enumValue)
                       ).ToArray();
        

        private string GetDescription(object enumValue)
        
            var descriptionAttribute = EnumType
                .GetField(enumValue.ToString())
                .GetCustomAttributes(typeof (DescriptionAttribute), false)
                .FirstOrDefault() as DescriptionAttribute;


            return descriptionAttribute != null
                ? descriptionAttribute.Description
                : enumValue.ToString();
        

        #region Nested type: EnumerationMember
        public class EnumerationMember
        
            public string Description  get; set; 
            public object Value  get; set; 
        
        #endregion
    

免责声明:我与 DevExpress 没有任何关系。 Telerik 也是一个很棒的图书馆。

【讨论】:

郑重声明,我不隶属于 DevExpress。 Telerik 也有非常好的库,他们的库甚至可能不需要这种技术。【参考方案12】:

尝试使用

<ComboBox ItemsSource="Binding Source=StaticResource ExampleEnumValues"
    SelectedValue="Binding Path=ExampleProperty" />

【讨论】:

这不起作用。组合框只会显示一个空文本,更改它不会做任何事情。我想在这里加入转换器将是最好的解决方案。【参考方案13】:

我创建了一个开源 CodePlex 项目来执行此操作。您可以从here 下载 NuGet 包。

<enumComboBox:EnumComboBox EnumType="x:Type demoApplication:Status" SelectedValue="Binding Status" />

【讨论】:

【参考方案14】:

代码

    public enum RULE
    
        [Description( "Любые, без ограничений" )]
        any,
        [Description( "Любые если будет три в ряд" )]
        anyThree,
        [Description( "Соседние, без ограничений" )]
        nearAny,
        [Description( "Соседние если будет три в ряд" )]
        nearThree
    

    class ExtendRULE
    
        public static object Values
        
            get
            
                List<object> list = new List<object>();
                foreach( RULE rule in Enum.GetValues( typeof( RULE ) ) )
                
                    string desc = rule.GetType().GetMember( rule.ToString() )[0].GetCustomAttribute<DescriptionAttribute>().Description;
                    list.Add( new  value = rule, desc = desc  );
                
                return list;
            
        
    

XAML

<StackPanel>
   <ListBox ItemsSource= "Binding Source=x:Static model:ExtendRULE.Values" DisplayMemberPath="desc" SelectedValuePath="value" SelectedValue="Binding SelectedRule"/>
   <ComboBox ItemsSource="Binding Source=x:Static model:ExtendRULE.Values" DisplayMemberPath="desc" SelectedValuePath="value" SelectedValue="Binding SelectedRule"/>                        
</StackPanel>

【讨论】:

【参考方案15】:

看到某些过于复杂的解决方案如何成为最微不足道的问题的“标准(反)模式”令人痛苦:实现MarkupExtension 的开销和复杂性,尤其是用属性装饰枚举值应该避免。只需实现一个数据模型。

通常,向用户显示枚举值名称是一个坏主意。枚举并不意味着在 UI 中显示。它们是在编程上下文中使用的常量。值名称不用于显示。它们是针对工程师的,因此这些名称通常使用特殊的语义和词汇,就像科学词汇并不意味着公众可以理解一样。不要犹豫,为显示的值创建一个专用源。

当涉及到本地化时,问题变得更加明显。 这就是为什么所有发布的答案都只是过度设计的原因。他们使一个非常简单的问题看起来像一个关键问题。 事实上,最简单的解决方案是最好的。原始问题的主题绝对是个例外。 我强烈建议不要提供任何答案。尽管它们可能有效,但它们给一个琐碎的问题增加了不必要的复杂性。

请注意,您始终可以通过调用静态 Enum.GetValuesEnum.GetNames 将枚举转换为其值或值名称的列表,它们都返回您可以直接分配给 ComboBox.ItemsSourceIEnumerable属性,例如,通过数据绑定。

IEnumerable<ExampleEnum> values = Enum.GetValues<ExampleEnum>();
IEnumerable<string> names = Enum.GetNames<ExampleEnum>();

通常,在定义枚举时,您不会考虑 UI。 枚举值名称不是根据 UI 设计规则选择的。 通常,UI 标签和文本通常是由没有开发人员或程序员背景的人创建的。他们通常会提供本地化应用程序所需的所有翻译。 不将 UI 与应用程序混合使用有很多很好的理由。 你永远不会在设计一个类并为它的属性命名时考虑到 UI(例如,DataGrid 列)。您可能希望列标题包含空格等。 异常消息针对开发人员而不是用户的原因相同。您绝对不想用属性装饰每个属性、每个异常、枚举或任何数据类型或成员,以便在特定 UI 上下文中提供对用户有意义的显示名称。 您不希望 UI 设计渗入您的代码库并污染您的类。 应用程序及其用户界面 - 这是两个不同的问题。 添加这个抽象或虚拟的额外分离层允许例如添加不应显示的枚举值。或者更一般地说,修改代码而不必破坏或修改 UI。

您应该使用 simple IValueConverter 或提供这些显示值作为绑定源的专用类,而不是使用属性和实现加载额外逻辑来提取它们的值. 坚持最常见的模式并为ComboBox 项目实现数据模型,其中类具有枚举类型的属性作为成员,这有助于您识别ComboBox.SelectedItem(以防您需要枚举值):

ExampleEnum.cs

// Define enumeration without minding any UI elements and context
public enum ExampleEnum 
 
    FooBar = 0, 
    BarFoo 

ExampleClass.cs

// Define readable enum display values in the UI context.
// Display names can come from a localizable resource.
public class BindingSource : INotifyPropertyChanged

    public BindingSource()
    
        ItemModels = new List<ItemModel> 
        
            new ItemModel  Label = "Foo Bar Display", Value = ExampleEnum.FooBar ,
            new ItemModel  Label = "Bar Foo Display", Value = ExampleEnum.BarFoo 
        
    

    public List<ItemModel> ItemModels  get; 

    private ItemModel selectedItemModel;
    public ItemModel SelectedItemModel  get => selectedItemModel; => set and notify; 

ItemModel.cs

public class ItemModel
   
    public string Label  get; set; 
    public ExampleEnum Value  get; set; 

MainWindow.xaml

<Window>
  <Window.DataContext>
    <BindingSource />
  </Window.DataContext>

  <ComboBox ItemsSource="Binding ItemModels"
            DisplayMemberName="DisplayValue"
            SelectedItem="Binding SelectedItemModel" />
</Window>

【讨论】:

以上是关于将枚举属性数据绑定到 WPF 中的组合框的主要内容,如果未能解决你的问题,请参考以下文章

WPF 数据绑定:如何使用 XAML 将枚举数据绑定到组合框? [复制]

DataGrid 数据绑定/更新中的 WPF 组合框不起作用

WPF 数据绑定组合框到列表<string>

将 ComboBoxes 绑定到枚举......在 Silverlight 中!

WPF 组合框和数据绑定到其他类

组合框中的 WPF 数据绑定彩色项目