How to Bind an Enum to a Combobox Control in Wpf

How to bind an enum to a combobox control in WPF?

You can do it from code by placing the following code in Window Loaded event handler, for example:

yourComboBox.ItemsSource = Enum.GetValues(typeof(EffectStyle)).Cast<EffectStyle>();

If you need to bind it in XAML you need to use ObjectDataProvider to create object available as binding source:

<Window x:Class="YourNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:StyleAlias="clr-namespace:Motion.VideoEffects">
<Window.Resources>
<ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="StyleAlias:EffectStyle"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
SelectedItem="{Binding Path=CurrentEffectStyle}" />
</Grid>
</Window>

Draw attention on the next code:

xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:StyleAlias="clr-namespace:Motion.VideoEffects"

Guide how to map namespace and assembly you can read on MSDN.

c# Wpf binding an enum to combobox

If you want to be able to simply bind an enum from your XAML you can write a markup extension class. I've written a blog post about it some time ago:
http://simonkatanski.blogspot.com/2013/02/enum-combobox-using-markupextension.html

Here's the code:

public class EnumValuesExtension : MarkupExtension
{
private Type _enumType;
private String _resourceName;
private bool _addEmptyValue = false;
// Enumeration type
public Type EnumType
{
set { _enumType = value; }
}
// Name of the class of the .resx file
public String ResourceName
{
set { _resourceName = value; }
}
// Add empty value flag
public Boolean AddEmptyValue
{
set { _addEmptyValue = value; }
}
public EnumValuesExtension()
{
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
// Enumeration type not passed through XAML
if (_enumType == null)
throw new ArgumentNullException("EnumType (Property not set)");
if (!_enumType.IsEnum)
throw new ArgumentNullException("Property EnumType must be an enum");
// Bindable properties list
List<dynamic> list = new List<dynamic>();

if (!String.IsNullOrEmpty(_resourceName))
{
// Name of the resource class
Type type = Type.GetType(_resourceName);
if (type == null)
throw new ArgumentException(
"Resource name should be a fully qualified name");
// We iterate through the Enum values
foreach (var enumName in Enum.GetNames(_enumType))
{
string translation = string.Empty;
var property = type.GetProperty(enumName,
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic);
// If there's not translation for specific Enum value,
// there'll be a message shown instead
if (property == null)
translation = String.Format(
"Field {0} not found in the resource file {1}",
enumName,
_resourceName);
else
translation = property.GetValue(null, null).ToString();

list.Add(GetNamed(translation, enumName));
}
// Adding empty row
if (_addEmptyValue)
list.Add(GetEmpty());
return list;
}
// If there's no resource provided Enum values will be used
// without translation
foreach (var enumName in Enum.GetNames(_enumType))
list.Add(GetNamed(enumName, enumName));

if (_addEmptyValue)
list.Add(GetEmpty());

return list;
}

// Create one item which will fill our ComboBox ItemSource list
private dynamic GetNamed(string translation, string enumName)
{
// We create a bindable context
dynamic bindableResult = new ExpandoObject();
// This dynamically created property will be
// bindable from XAML (through DisplayMemberPath or wherever)
bindableResult.Translation = translation;
// We're setting the value, which will be passed to SelectedItem
// of the ComboBox
bindableResult.Enum = enumName;
return bindableResult;
}

// Create one empty item which will fill our ComboBox ItemSource list
private dynamic GetEmpty()
{
dynamic bindableResult = new ExpandoObject();
bindableResult.Translation = String.Empty;
bindableResult.Enum = null;
return bindableResult;
}
}

You can use this class in your code like this:

<StackPanel>
<ComboBox Height="100" Width="200"
SelectedValuePath="Enum"
DisplayMemberPath="Translation"
ItemsSource="{Binding Source={local:EnumValues EnumType=local:TestEnum}}"
Margin="98,0,76,0"
SelectedValue="{Binding SelectedItemInYourViewModel}"/>
</StackPanel>

All you do then is pass your Enum as the Enum type in the above xaml. This way you can have a generic way of using enums from xaml.

The version I've pasted here and the one in the blog has extra code for hot-switching values in combo with their translated equivalents (if you are working on multi-language application) - you should be able to easily remove that code.

Cant bind enum to combobox wpf mvvm

You are trying to bind to a private variable, instead, your enum should be exposed as a Property.

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

Also, Discosultan has already solved another problem for you.

Cant bind a property as enum to combobox in wpf mvvm

Honestly, I don't really know what went wrong in your code, but I can give you a working example without any fancy converter stuff:

Suppose you have the following window-content:

<Grid x:Name="grid1">
<ComboBox ItemsSource="{Binding SelectableRanks}" SelectedItem="{Binding SelectedRank}"/>
</Grid>

And you initialize the datacontext in the window constructor:

public MainWindow()
{
InitializeComponent();
grid1.DataContext = new RankSelectionVM();
}

And this is your viewmodel:

public class RankSelectionVM
{
private RankType _SelectedRank;
public RankType SelectedRank
{
get { return _SelectedRank; }
set { _SelectedRank = value; }
}

private RankType[] _rankTypes;
public RankType[] SelectableRanks
{
get
{
return _rankTypes ??
(_rankTypes = Enum.GetValues(typeof(RankType)).Cast<RankType>().ToArray());
}
}
}

public enum RankType
{
StringValue1,
StringValue2,
StringValue3
}

It doesn't have any INotifyPropertyChanged or any converters attached, but place a breakpoint in the SelectedRank setter - it should break when you select a value. If this code works for you, you have to find what you did differently to get a not-working code in your project. Otherwise you may have some very strange issue that needs special care.

bind enum to Combobox On CUSTOM CONTROL

You can use Resources as suggested in comments.

full XAML:

<UserControl x:Class="WpfControlFoo.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:App="myNamespaceWhereTheEnumIsLocated"
mc:Ignorable="d" Width="799" Height="107">
<UserControl.Resources>
<ObjectDataProvider
MethodName="GetDict"
ObjectType="{x:Type App:EnumDescriptionValueDict}"
x:Key="EnumDescriptionDict">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="App:Transmission"></x:Type>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</UserControl.Resources>
<ComboBox
ItemsSource="{Binding Source={StaticResource EnumDescriptionDict}}"
DisplayMemberPath="Key"
SelectedValuePath="Value"/>
</UserControl>

Binding combobox with an Enumeration value and get the selected item in the form of enum

First create a ObjectDataProvider in xaml as follows inside Resource tag :

<ObjectDataProvider  x:Key="odpEnum"
MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:Comparators"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:EnumDescriptionConverter x:Key="enumDescriptionConverter"></local:EnumDescriptionConverter>

Now in the above code sample the sys:Enum is having an alias sys which is coming from namespace xmlns:sys="clr-namespace:System;assembly=mscorlib". So this needs to be added.

Add a combobox as follows :

<ComboBox Grid.Row="1" Grid.Column="1"  Height="25" Width="100" Margin="5" 
ItemsSource="{Binding Source={StaticResource odpEnum}}"
SelectedItem="{Binding Path=MySelectedItem}"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource enumDescriptionConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Let me consider you have a enum type as follows :

public enum Comparators
{
[Description("Application")]
Application,
[Description("Application Type")]
ApplicationType,
[Description("Inspection Name")]
InspectionName,
[Description("Component Type")]
ComponentType
}

so keep it in viewmodel section (outside the view model but inside the same namespace as that of viewmodel)

Now create a property in viewmodel as follows to get the selectedItem from XAML ComboBox

private Comparators _MySelectedItem;
public Comparators MySelectedItem
{
get { return _MySelectedItem; }
set
{
_MySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}
}

Create a converter class as follows :--

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

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Comparators)value;
string description = GetEnumDescription(myEnum);
return description;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
}

when you will run this sample then you will find you will get selectedItem as of type enumeration in _MySelectedItem = value; in the property of the viewmodel.



Related Topics



Leave a reply



Submit