WPF Binding a ListBox to an enum, displaying the Description Attribute
Yes, it is possible. This will do it. Say we have the enum
public enum MyEnum
{
[Description("MyEnum1 Description")]
MyEnum1,
[Description("MyEnum2 Description")]
MyEnum2,
[Description("MyEnum3 Description")]
MyEnum3
}
Then we can use the ObjectDataProvider as
xmlns:MyEnumerations="clr-namespace:MyEnumerations"
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="MyEnumValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="MyEnumerations:MyEnum" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
And for the ListBox we set the ItemsSource to MyEnumValues and apply an ItemTemplate with a Converter.
<ListBox Name="c_myListBox" SelectedIndex="0" Margin="8"
ItemsSource="{Binding Source={StaticResource MyEnumValues}}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in the converter we get the description and return it
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;
}
}
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
}
The GetEnumDescription method should probably go somewhere else but you get the idea :)
Check GetEnumDescription as extension method.
Another solution would be a custom MarkupExtension that generates the items from enum type. This makes the xaml more compact and readable.
using System.ComponentModel;
namespace EnumDemo
{
public enum Numbers
{
[Description("1")]
One,
[Description("2")]
Two,
Three,
}
}
Example of usage:
<Window x:Class="EnumDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EnumDemo">
<ListBox ItemsSource="{local:EnumToCollection EnumType={x:Type local:Numbers}}"/>
</Window>
MarkupExtension implementation
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Markup;
namespace EnumDemo
{
public class EnumToCollectionExtension : MarkupExtension
{
public Type EnumType { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (EnumType == null) throw new ArgumentNullException(nameof(EnumType));
return Enum.GetValues(EnumType).Cast<Enum>().Select(EnumToDescriptionOrString);
}
private string EnumToDescriptionOrString(Enum value)
{
return value.GetType().GetField(value.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false)
.Cast<DescriptionAttribute>()
.FirstOrDefault()?.Description ?? value.ToString();
}
}
}
If you bind to the Enum, you could probably convert this to the description through an IValueConverter.
See Binding ComboBoxes to enums... in Silverlight! for a description on how to accomplish this.
See http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx for more information.