heliar heliar - 4 months ago 78
C# Question

WPF DatagridComboBoxColumn displaymemberpath description attribute

DataGrid has AutoGeneratedColumns = true.
Some of the properties are enum so the corresponding columns are DatagridComboBoxColumn.
Enum definitions have a Description Attribute as follows:

public enum MyEnum
{
[Description("first")]
FirstEnum,

[Description("second")]
SecondEnum
}


I already have a utility method to display Description attributes in a ComboBox :

public class EnumToItemsSource : MarkupExtension
{
private readonly Type _type;

public EnumToItemsSource(Type type)
{
_type = type;
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return Enum.GetValues(_type).Cast<object>().Select(e => new { Value = e,
Description = GetEnumDescription((Enum)e) });
}

public static string GetEnumDescription(Enum enumObj)
{
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
object[] attributes = fieldInfo.GetCustomAttributes(false);
if (attributes.Length == 0)
return enumObj.ToString();
else
{
DescriptionAttribute attrib = attributes.OfType<DescriptionAttribute>().FirstOrDefault();
if (attrib != null)
return attrib.Description;
else
return "No description";
}
}
}


And I use it in xaml as follows :

<ComboBox ItemsSource="{utils:EnumToItemsSource {x:Type myenums:MyEnum}}"
DisplayMemberPath="Description"
SelectedValuePath="Value"
SelectedValue="{Binding SomeProperty}"/>


Now my question is, how can I apply this to an auto generated column?

EDIT First try

I've try a first solution by doing it in the AutoGeneratingColumn event handler :

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
DataGridComboBoxColumn col = e.Column as DataGridComboBoxColumn;
if (col != null)
{
col.ItemsSource = EnumToIEnumerable.GetIEnumerable(e.PropertyType);
col.DisplayMemberPath = "Value";
col.SelectedValuePath = "Key";
col.SelectedValueBinding = new Binding(e.PropertyName);
}
}


For that, I had to write a new helper static method to provide the list for the combobox items source :

public static class EnumToIEnumerable
{
public static IEnumerable<KeyValuePair<Enum, string>> GetIEnumrable(Type type)
{
return Enum.GetValues(type).Cast<Enum>().Select((e) => new KeyValuePair<Enum, string>(e,
EnumDescriptionConverter.GetEnumDescription((Enum)e)));
}
}


It's working for displaying the description. But the programm cannot convert SelectedValue to the bound property. It throws silent exceptions and the combobox is red lined.

I try to translate the error message in english :

Conversion of EnumConverter is not possible from System.Collections.Generic.KeyValuePair
System.Windows.Data Error: 7 : ConvertBack cannot convert value '[Surface, m²]' (type 'KeyValuePair`2'). BindingExpression:Path=TypeQuantite; DataItem='MscaGridLineViewModel' (HashCode=39414053); target element is 'TextBlockComboBox' (Name=''); target property is 'SelectedItem' (type 'Object') NotSupportedException:'System.NotSupportedException: Conversion de EnumConverter impossible à partir de System.Collections.Generic.KeyValuePair`2[[System.Enum, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].


I don't understand why it's written target property is 'SelectedItem' because the SelectedValuePath contains an Enum object and the SelectedValueBinding binds it to a Property of Type "MyEnum" which is an enum.

Answer

The answer : I only had to add the line col.SelectedItemBinding = null;

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    DataGridComboBoxColumn col = e.Column as DataGridComboBoxColumn;
    if (col != null)
    {
        col.ItemsSource = EnumToIEnumerable.GetIEnumerable(e.PropertyType);
        col.DisplayMemberPath = "Value";
        col.SelectedValuePath = "Key";
        col.SelectedValueBinding = new Binding(e.PropertyName);
        col.SelectedItemBinding = null;
    }
}