Introduction
Any real world application would like to bind Enum values to a ComboBox
. So it is always better to have a common code that will do the logic.
Using the Code
I have a helper class which exposes a property to get the enum type so that I can resolve the enum values.
public static Type GetEnum(DependencyObject obj)
{
return (Type)obj.GetValue(EnumProperty);
}
public static void SetEnum(DependencyObject obj, string value)
{
obj.SetValue(EnumProperty, value);
}
public static readonly DependencyProperty EnumProperty =
DependencyProperty.RegisterAttached("Enum", typeof(Type),
typeof(EnumHelper), new PropertyMetadata(null, OnEnumChanged));
Get the values of the enum and set it as ComboBox ItemsSource
.
private static void OnEnumChanged(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
var control = sender as ItemsControl;
if (control != null)
{
if (e.NewValue != null)
{
var _enum = Enum.GetValues(e.NewValue as Type);
control.ItemsSource = _enum;
}
}
}
Now the ComboBox
will bind to the enum values, if we set the enum value in XAML.
public enum Designation
{
SoftwareEngineer,
TeamLead,
ProductManager
}
<ComboBox x:Name="Designation" Margin="5" Grid.Row="5"
SelectedItem="{Binding Designation, Mode=TwoWay}"
local:EnumHelper.Enum="{x:Type local:Designation}">
</ComboBox>
Look at the names of items. They are not well spaced. It should be Product Manager instead of ProductManager. For this, we will use the Display
attribute of enum values. Further, we can also use the Description
attribute to let the user see more details.
I have modified my enum to look like below:
public enum Designation
{
[Display(Name="Software Engineer")]
[Description("Software engineer responsible for core development.")]
SoftwareEngineer,
[Display(Name = "Team Lead")]
[Description("Team lead responsible for leading a small team of 5 to 10 members.")]
TeamLead,
[Display(Name = "Product Manager")]
[Description("Product manager responsible for core management.")]
ProductManager
}
Also our helper class should expose another property to get the values of attributes and set it wherever needed. For example, in this case I will show the description as a tooltip and display as text.
public static bool GetMoreDetails(DependencyObject obj)
{
return (bool)obj.GetValue(MoreDetailsProperty);
}
public static void SetMoreDetails(DependencyObject obj, bool value)
{
obj.SetValue(MoreDetailsProperty, value);
}
public static readonly DependencyProperty MoreDetailsProperty =
DependencyProperty.RegisterAttached("MoreDetails",
typeof(bool), typeof(EnumHelper), new PropertyMetadata(false, OnMoreDetailsChanged));
We are getting the attribute values and set it in the appropriate places. We expect the user to set this property in any DataTemplate
so that we can get the underlying enum object as a DataContext
.
var array = fieldInfo.GetCustomAttributes(false);
if (array.Length == 0)
{
if (control is TextBlock)
{
((TextBlock)control).Text = enumobject.ToString();
}
else if (control is ContentControl)
{
((ContentControl)control).Content = enumobject;
}
return;
}
foreach (var o in array)
{
if (o is DescriptionAttribute)
{
control.ToolTip = ((DescriptionAttribute) o).Description;
}
else if (o is DisplayAttribute)
{
if (control is TextBlock)
{
((TextBlock) control).Text = ((DisplayAttribute) o).Name;
}
else if (control is ContentControl)
{
((ContentControl)control).Content = ((DisplayAttribute)o).Name;
}
}
}
Let's add a DataTemplate
to the ComboBox
:
<DataTemplate>
<TextBlock local:EnumHelper.MoreDetails="True"/>
</DataTemplate>