Databinding an enum property to a ComboBox in WPF
Asked Answered
P

15

281

As an example take the following code:

public enum ExampleEnum { FooBar, BarFoo }

public class ExampleClass : INotifyPropertyChanged
{
    private ExampleEnum example;

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

I want a to databind the property ExampleProperty to a ComboBox, so that it shows the options "FooBar" and "BarFoo" and works in mode TwoWay. Optimally I want my ComboBox definition to look something like this:

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

Currently I have handlers for the ComboBox.SelectionChanged and ExampleClass.PropertyChanged events installed in my Window where I do the binding manually.

Is there a better or some kind of canonical way? Would you usually use Converters and how would you populate the ComboBox with the right values? I don't even want to get started with i18n right now.

Edit

So one question was answered: How do I populate the ComboBox with the right values.

Retrieve Enum values as a list of strings via an ObjectDataProvider from the static Enum.GetValues method:

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

This I can use as an ItemsSource for my ComboBox:

<ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}"/>
Pandemonium answered 12/9, 2008 at 11:38 Comment(1)
I explored this and have a solution that you can use (complete with localization) in WPF located here.Merit
H
222

You can create a custom markup extension.

Example of usage:

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

At the top of your XAML:

    xmlns:my="clr-namespace:namespace_to_enumeration_extension_class

and then...

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

And the implementation...

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) // or IXamlServiceProvider for UWP and WinUI
    {
      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; }
    }
  }
Housemaid answered 9/12, 2010 at 13:35 Comment(15)
@Gregor S. what my:Enumeration is ?Trippet
@Crown 'my' is namespace prefix which you declare at top of you xaml file: e.g xmlns:my="clr-namespace:namespace_to_enumeration_extension_class. Enumeration is short for EnumerationExtension, in xaml you don't have to write the whole extension class name.Housemaid
Using this code above is it still possible to save the value of the selected item to User Settings and read it back?Clung
Yes, just set/get CurrentStatus property in your viewmodel.Housemaid
+1, but the amount of code required by WPF to accomplish simpliest of things is really headspinningVitrics
I don't really like the way it makes you use a reference to a part of your model - the enumeration type - in the view, in the ItemsSource param. In order to keep the view and the model decoupled I would need to create a copy of the enumeration in the ViewModel and code ViewModel to translate between the two... Which would make the solution not that simple any more. Or is there a way to supply the type itself from ViewModel?Extrasystole
Another limitation is that you can't do this if you have multiple languages.Habituate
If you get into the Error "EnumerationExtension” does not include a constructor that has the specified number of arguments try using ItemsSource="{Binding Source={my:Enumeration EnumType={x:Type my:Status}}}"Mid
Cant get that namespace part... Everything gets highlighted as "does not exist".Grunberg
@RiverWilliamson your attribute can be culture sensitive, in a way that you can specify the resource name and typeLamppost
I've encountered this problem several times over the years, and using your MarkupExtension provides the cleanest mechanism I've seen for not only using a proxy class in lieu of an enum value auto-magically, but allowing it to be localized. I abstracted the bit that does the reflection into a helper that can be used in code, and now all my enum description stuff (for XAML or reports) is funneled through one class, then used by the MarkupExtension you have here. Nice work!Cofield
I was having a big problem with the description display, then I overrided ToString on the EnumerationMember class to return description and now it works like a 7.62mm bullet.Anhydride
can you show where "CurrentStatus" property is? Is that in the xaml.cs file? I'm not succeeding in binding to SelectedValueStacistacia
I am also trying to find out where "CurrentStatus" is because I have a Description attribute that has numbers and letters (1120S) that will not assign a value correctly when it is selected. It displays properly in the dropdown, but when selected it doesn't assign the value to my viewmodelStereopticon
Does the MarkupExtension type exist in WPF core 6? How can I include it?Estis
D
209

In the viewmodel you can have:

public MyEnumType SelectedMyEnumType 
{
    get { return _selectedMyEnumType; }
    set { 
            _selectedMyEnumType = value;
            OnPropertyChanged("SelectedMyEnumType");
        }
}

public IEnumerable<MyEnumType> MyEnumTypeValues
{
    get
    {
        return Enum.GetValues(typeof(MyEnumType))
            .Cast<MyEnumType>();
    }
}

In XAML the ItemSource binds to MyEnumTypeValues and SelectedItem binds to SelectedMyEnumType.

<ComboBox SelectedItem="{Binding SelectedMyEnumType}" ItemsSource="{Binding MyEnumTypeValues}"></ComboBox>
Demb answered 27/4, 2011 at 11:13 Comment(3)
This worked fabulously in my Universal app, and was very easy to implement. Thank you!Mangrove
This works excellent and needs far, far less code as the selected answer.Frida
Very short and very efficient, thanks. Actually there is no more .Cast(), so I used ... return (IEnumerable<MyEnumType>)System.Enum.GetValues(typeof(MyEnumType));Johnson
J
123

I prefer not to use the name of enum in UI. I prefer use different value for user (DisplayMemberPath) and different for value (enum in this case) (SelectedValuePath). Those two values can be packed to KeyValuePair and stored in dictionary.

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 */; }
}

EDIT: Compatible with the MVVM pattern.

Joesphjoete answered 13/9, 2012 at 22:26 Comment(11)
I think your answer is underrated, it seems the best option given what ComboBox itself expects. Perhaps you could put a dictionary builder in the getter, using Enum.GetValues, but that wouldn't solve the part of names to be displayed. In the end, and specially if I18n is implemented, you'll have to manually change stuff if the enum changes, anyway. But enums aren't supposed to change often, if at all, are they? +1Narwhal
Allow me to fix it as you wrote in the comment: private static readonly Dictionary<ExampleEnum, string> EnumMapping = new Dictionary<ExampleEnum, string>() { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, }; public Dictionary<ExampleEnum, string> ExampleEnumsWithCaptions { get { return EnumMapping; } } :)Photocopier
This answer is awesome AND it allows to localize the enums descriptions... Thanks for this!Saturninasaturnine
This solution is very good because it handles both enum and localization with less code than other solutions!Interpretative
The problem with Dictionary is that the keys are ordered by hash value so there is little control over that. Though a little more verbose, I used List<KeyValuePair<enum, string>> instead. Nice idea.Boabdil
@Joesphjoete @Photocopier new fix: public Dictionary<ExampleEnum, string> ExampleEnumsWithCaptions { get; } = new Dictionary<ExampleEnum, string>() { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, };Sundberg
@JinJi Updated to C# 6. Your fix makes code shorter. Thanks.Joesphjoete
I used this pattern, I like its shortness and elegance. Personally, I swapped Key and Value because in my head a dictionary would hold string keys to enum values. But I guess it doesn't matter.Bencher
This almost works for me. The drop down items look correct, but the selection in the combobox show both the key and value. For the example above, selecting the first option show's [FooBar, Foo Bar]Ionosphere
@Ionosphere Are you sure that you have used DisplayMemberPath="Value". It's telling ComboBox that only the Value is for UI.Joesphjoete
@Joesphjoete thanks for the comment! It was actually some other theming that was being applied from a resource dictionary, unbeknownst to me. Removing that fixed the issueIonosphere
S
44

I don't know if it is possible in XAML-only but try the following:

Give your ComboBox a name so you can access it in the codebehind: "typesComboBox1"

Now try the following

typesComboBox1.ItemsSource = Enum.GetValues(typeof(ExampleEnum));
Skyler answered 12/9, 2008 at 11:54 Comment(0)
I
35

Use ObjectDataProvider:

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

and then bind to static resource:

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

Find this solution at this blog

Ingravescent answered 27/1, 2015 at 14:58 Comment(4)
Nice answer. Incidentally, it saves you from having to worry about a Converter for the enum-to-string issue.Alinaaline
Linked Solution seems dead (korean or japanese Text?). If I put your code to my XAML Resources it says Enum is not supported in a WPF project.Kt
You need to add 'xmlns:System="clr-namespace:System;assembly=mscorlib"' in the Window tag xlmns defintionsPricecutting
Simple, elegant solution, this needs to be promoted up!Toddle
I
24

Based on the accepted but now deleted answer provided by ageektrapped I created a slimmed down version without some of the more advanced features. All the code is included here to allow you to copy-paste it and not get blocked by link-rot.

I use the System.ComponentModel.DescriptionAttribute which really is intended for design time descriptions. If you dislike using this attribute you may create your own but I think using this attribute really gets the job done. If you don't use the attribute the name will default to the name of the enum value in code.

public enum ExampleEnum {

  [Description("Foo Bar")]
  FooBar,

  [Description("Bar Foo")]
  BarFoo

}

Here is the class used as the items source:

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

}

You can use it in XAML like this:

<Windows.Resources>
  <local:EnumItemsSource
    x:Key="ExampleEnumItemsSource"
    Type="{x:Type local:ExampleEnum}"/>
</Windows.Resources>
<ComboBox
  ItemsSource="{StaticResource ExampleEnumItemsSource}"
  SelectedValue="{Binding ExampleProperty, Converter={StaticResource ExampleEnumItemsSource}}"/> 
Inch answered 7/10, 2011 at 9:35 Comment(0)
B
8

My favorite way to do this is with a ValueConverter so that the ItemsSource and SelectedValue both bind to the same property. This requires no additional properties to keep your ViewModel nice and clean.

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

And the definition of the 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;
  }
}

This converter will work with any enum. ValueDescription is just a simple class with a Value property and a Description property. You could just as easily use a Tuple with Item1 and Item2, or a KeyValuePair with Key and Value instead of Value and Description or any other class of your choice as long as it has can hold an enum value and string description of that enum value.

Bono answered 13/7, 2017 at 19:12 Comment(3)
Nice answer! For the ValueDescription class, the Description property may be omitted if not needed. A simple class with only Value property also works!Somatic
Also, if you want to bind to a RadioButton, then the Convert method must return a list of strings, i.e. .Select(e => e.ToString()), instead of using the ValueDescription class.Somatic
Instead of ValueDescription also a KeyValuePair could be used, like shown hereLightproof
K
7

you can consider something like that:

  1. define a style for textblock, or any other control you want to use to display your enum:

    <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>
    
  2. define your style for ComboBoxItem

    <Style TargetType="{x:Type ComboBoxItem}">
        <Setter Property="ContentTemplate">
            <Setter.Value>
                <DataTemplate>
                    <TextBlock Tag="{Binding}" Style="{StaticResource enumStyle}"/>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
  3. add a combobox and load it with your enum values:

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

if your enum is large, you can of course do the same in code, sparing a lot of typing. i like that approach, since it makes localization easy - you define all the templates once, and then, you only update your string resource files.

Kanarese answered 16/9, 2008 at 16:6 Comment(1)
the SelectedValuePath="Content" helped me here. I have my ComboBoxItems as string values, and kept getting can't convert ComboBoxItem to my Enum Type. ThanksIives
B
5

Here is a generic solution using a helper method. This can also handle an enum of any underlying type (byte, sbyte, uint, long, etc.)

Helper Method:

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

View Model:

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

ComboBox:

<ComboBox
    SelectedValue       ="{Binding SearchType}"
    ItemsSource         ="{Binding EnumSearchTypes}"
    DisplayMemberPath   ="Name"
    SelectedValuePath   ="Value"
/>
Bathulda answered 20/2, 2013 at 9:54 Comment(0)
M
2

If you are using a MVVM, based on @rudigrobler answer you can do the following:

Add the following property to the ViewModel class

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

Then in the XAML do the following:

<ComboBox ItemsSource="{Binding ExampleEnumValues}" ... />
Manamanacle answered 26/4, 2017 at 3:46 Comment(0)
C
2

It's a pain to see all to see how certain overly complicated solutions become a "standard (anti-)pattern" for the most trivial problems: the overhead and complexity of implementing a MarkupExtension and especially decorating enum values with attributes should be avoided. Simply implement a data model.

Generally, displaying the enumeration value names to the user is a bad idea. Enumerations are not meant to be displayed in the UI. They are constants that are used in a programmatic context. The value names are not meant for display. They are meant to address the engineer, hence the names usually use special semantics and vocabulary, same as scientific vocabulary is not meant to be understood by the public. Don't hesitate to create a dedicated source for the displayed values.

The problem becomes more evident when localization gets involved.
That's why all posted answers are simply over engeineered. They make a very simple problem look like a critical issue.
It's a fact that the most trivial solution is the best. The subject of the original question is most definitely not an exception.
I highly recommend against any of the provided answers. Although they may work, they add unnecessary complexity to a trivial problem.

Note, that you can always convert an enum to a list of its values or value names by calling the static Enum.GetValues or Enum.GetNames, which both return an IEnumerable that you can directly assign to the ComboBox.ItemsSource property e.g.,via data binding.

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

Usually, when defining an enumeration, you don't have UI in mind.
Enumeration value names are not chosen based on UI design rules.
Usually, UI labels and text in general are created by people with no developer or programmer background. They usually provide all the required translations to localize the application.
There are many good reasons not to mix UI with the application.
You would never design a class and name its properties with UI (e.g., DataGrid columns) in mind. You may want your column header to contain whitespaces etc.
Same reason why exception messages are directed at developers and not users. You definitely don't want to decorate every property, every exception, enum or whatever data type or member with attributes in order to provide a display name that makes sense to the user in a particular UI context.
You don't want to have UI design bleed into your code base and polute your classes.
Application and its user interface - this are two different problems.
Adding this abstract or virtual extra layer of separation allows e.g., to add enum values that should not be displayed. Or more general, modify code without having to break or modify the UI.

Instead of using attributes and implementing loads of additional logic to extract their values (using reflection), you should use a simple IValueConverter or a dedicated class that provides those display values as a binding source.
Stick to the most common pattern and implement a data model for the ComboBox items, where the class has a property of the enum type as member, that helps you to identify the ComboBox.SelectedItem (in case you need the enum value):

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="Label"
            SelectedItem="{Binding SelectedItemModel}" />
</Window>
Chrisy answered 17/12, 2021 at 1:1 Comment(3)
nice approach and considerations! Though I'd put enum labels in view model or even in view. And I'd like it to be more generic, because composing ItemModel for each enum will require a lot of typing :) BTW DisplayMemberName="DisplayValue" in ComboBox seems to be a typo - aren't we binding to Label property?Argenteuil
Thanks, for your useful review and comment. Of course that was a typo that escaped my attention. There is no such property named "DisplayValue". It must be "Label" that's correct. Regarding the component association, the enum must be defined so that it can be used without violating MVVM (when we are applying the MVVM design pattern). Because we introduced this type to gracefully display an enum's display value (which means it is used in the view), it should be defined in the view model of the view model is also referencing it, or in the view of this is an exclusive object of the view.Chrisy
This example exposes the items via data binding where the data source is the view model. Making this a generic type is also a good idea. Just be aware that genetic types are complicated to declare in XAML.Chrisy
R
1

This is a DevExpress specific answer based on the top-voted answer by Gregor S. (currently it has 128 votes).

This means we can keep the styling consistent across the entire application:

enter image description here

Unfortunately, the original answer doesn't work with a ComboBoxEdit from DevExpress without some modifications.

First, the XAML for the ComboBoxEdit:

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

Needsless to say, you will need to point xamlExtensions at the namespace that contains the XAML extension class (which is defined below):

xmlns:xamlExtensions="clr-namespace:XamlExtensions"

And we have to point myEnum at the namespace that contains the enum:

xmlns:myEnum="clr-namespace:MyNamespace"

Then, the enum:

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

The problem in with the XAML is that we can't use SelectedItemValue, as this throws an error as the setter is unaccessable (bit of an oversight on your part, DevExpress). So we have to modify our ViewModel to obtain the value directly from the object:

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");
    }
}

For completeness, here is the XAML extension from the original answer (slightly renamed):

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

Disclaimer: I have no affiliation with DevExpress. Telerik is also a great library.

Rightness answered 30/6, 2015 at 15:48 Comment(1)
For the record, I am not affiliated with DevExpress. Telerik also has very fine libraries, and this technique might not even be necessary for their library.Rightness
S
0

Try using

<ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}"
    SelectedValue="{Binding Path=ExampleProperty}" />
Skyler answered 12/9, 2008 at 12:29 Comment(1)
This doesn't work. The combobox will just show an empty text and changing it won't do anything. I guess throwing in a converter here would be the best solution.Pandemonium
D
0

I've created an open source CodePlex project that does this. You can download the NuGet package from here.

<enumComboBox:EnumComboBox EnumType="{x:Type demoApplication:Status}" SelectedValue="{Binding Status}" />
Deify answered 10/11, 2016 at 21:41 Comment(0)
R
0

Code

    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>
Remount answered 15/1, 2021 at 18:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.