278

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}}"/>
Maximilian
  • 4,728
  • 5
  • 29
  • 28
  • 4
    I explored this and have a solution that you can use (complete with localization) in WPF located [here](http://www.ageektrapped.com/blog/the-missing-net-7-displaying-enums-in-wpf/). – ageektrapped Sep 19 '08 at 00:52

15 Answers15

219

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; }
    }
  }
Luke Vanzweden
  • 466
  • 3
  • 15
Gregor Slavec
  • 4,814
  • 1
  • 26
  • 24
  • 8
    @Gregor S. what my:Enumeration is ? – joshua Jul 10 '12 at 06:53
  • 15
    @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. – Gregor Slavec Jul 10 '12 at 07:20
  • Using this code above is it still possible to save the value of the selected item to User Settings and read it back? – papaiatis Jul 23 '12 at 07:42
  • Yes, just set/get CurrentStatus property in your viewmodel. – Gregor Slavec Jul 23 '12 at 10:40
  • 47
    +1, but the amount of code required by WPF to accomplish simpliest of things is really headspinning – Konrad Morawski Aug 29 '12 at 14:36
  • 1
    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? – lampak Aug 31 '12 at 16:01
  • 7
    Another limitation is that you can't do this if you have multiple languages. – River-Claire Williamson Jan 22 '13 at 20:16
  • 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}}}"` – Markus Weber Mar 30 '16 at 14:12
  • Cant get that namespace part... Everything gets highlighted as "does not exist". – C4d Aug 31 '16 at 15:04
  • 1
    @RiverWilliamson your attribute can be culture sensitive, in a way that you can specify the resource name and type – Davi Fiamenghi Dec 12 '16 at 18:24
  • 1
    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! – outbred Dec 15 '16 at 22:20
  • 1
    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. – Felype Feb 09 '17 at 16:56
  • 1
    can you show where "CurrentStatus" property is? Is that in the xaml.cs file? I'm not succeeding in binding to SelectedValue – vbp13 Jan 23 '19 at 21:02
  • 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 viewmodel – HeedfulCrayon Mar 06 '19 at 16:28
  • Does the MarkupExtension type exist in WPF core 6? How can I include it? – AdrAs Jan 09 '22 at 12:38
205

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>
ASh
  • 34,632
  • 9
  • 60
  • 82
user659130
  • 2,059
  • 1
  • 12
  • 2
  • 1
    This worked fabulously in my Universal app, and was very easy to implement. Thank you! – Nathan Strutz Nov 09 '17 at 21:03
  • 2
    This works excellent and needs far, far less code as the selected answer. – j__ Feb 25 '21 at 15:08
  • Very short and very efficient, thanks. Actually there is no more .Cast(), so I used ... return (IEnumerable)System.Enum.GetValues(typeof(MyEnumType)); – tom2051 Jun 29 '22 at 14:39
120

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.

CoperNick
  • 2,413
  • 2
  • 21
  • 26
  • 19
    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? +1 – heltonbiker Oct 14 '13 at 14:21
  • Allow me to fix it as you wrote in the comment: `private static readonly Dictionary EnumMapping = new Dictionary() { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, }; public Dictionary ExampleEnumsWithCaptions { get { return EnumMapping; } }` :) – Pragmateek Aug 05 '14 at 15:04
  • 4
    This answer is awesome AND it allows to localize the enums descriptions... Thanks for this! – Shay May 04 '17 at 08:28
  • 3
    This solution is very good because it handles both enum and localization with less code than other solutions! – hfann Jun 22 '17 at 22:20
  • 2
    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> instead. Nice idea. – Kevin Brock Mar 30 '18 at 14:38
  • 3
    @CoperNick @Pragmateek new fix: `public Dictionary ExampleEnumsWithCaptions { get; } = new Dictionary() { {ExampleEnum.FooBar, "Foo Bar"}, {ExampleEnum.BarFoo, "Reversed Foo Bar"}, //{ExampleEnum.None, "Hidden in UI"}, };` – Jinjinov Nov 15 '18 at 13:37
  • 1
    @JinJi Updated to C# 6. Your fix makes code shorter. Thanks. – CoperNick Nov 15 '18 at 17:54
  • 1
    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. – LWChris Feb 04 '20 at 11:38
  • 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]` – chanban Jan 17 '23 at 23:02
  • @chanban Are you sure that you have used DisplayMemberPath="Value". It's telling ComboBox that only the Value is for UI. – CoperNick Jan 18 '23 at 15:32
  • @CoperNick 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 issue – chanban Jan 24 '23 at 00:56
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));
rudigrobler
  • 17,045
  • 12
  • 60
  • 74
33

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

druss
  • 1,820
  • 19
  • 18
  • 1
    Nice answer. Incidentally, it saves you from having to worry about a `Converter` for the enum-to-string issue. – DonBoitnott Nov 21 '17 at 16:57
  • 1
    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. – Sebastian Jun 14 '18 at 09:28
  • 2
    You need to add 'xmlns:System="clr-namespace:System;assembly=mscorlib"' in the Window tag xlmns defintions – yoel halb Jan 13 '21 at 02:53
  • 1
    Simple, elegant solution, this needs to be promoted up! – Scyssion Aug 03 '21 at 23:18
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}}"/> 
Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
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.

Nick
  • 4,556
  • 3
  • 29
  • 53
  • Nice answer! For the `ValueDescription` class, the `Description` property may be omitted if not needed. A simple class with only `Value` property also works! – pogosama Oct 13 '17 at 13:06
  • 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. – pogosama Oct 13 '17 at 13:52
  • Instead of `ValueDescription` also a `KeyValuePair` could be used, like [shown here](https://stackoverflow.com/a/16838203/9758687) – Coden Dec 26 '19 at 20:32
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.

ASh
  • 34,632
  • 9
  • 60
  • 82
Greg
  • 565
  • 1
  • 5
  • 13
  • the SelectedValuePath="Content" helped me here. I have my ComboBoxItems as string values, and kept getting can't convert ComboBoxItem to my Enum Type. Thanks – adriaanp May 13 '09 at 03:43
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"
/>
Jack
  • 4,684
  • 2
  • 29
  • 22
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}" ... />
MotKohn
  • 3,485
  • 1
  • 24
  • 41
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="DisplayValue"
            SelectedItem="{Binding SelectedItemModel}" />
</Window>
BionicCode
  • 1
  • 4
  • 28
  • 44
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.

Contango
  • 76,540
  • 58
  • 260
  • 305
  • 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. – Contango Jun 30 '15 at 15:53
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}" />
LawMan
  • 3,469
  • 1
  • 29
  • 32
0

Try using

<ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}"
    SelectedValue="{Binding Path=ExampleProperty}" />
rudigrobler
  • 17,045
  • 12
  • 60
  • 74
  • 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. – Maximilian Sep 12 '08 at 12:48
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>
proa
  • 109
  • 1
  • 5