Thursday 4 August 2011

Binding a DataGrid Column to an ComboBox containing an enumeration

In WPF it’s quite easy to bind a combo box to an enumerated type.  Unfortunately in Silverlight, I found myself in for a world of pain.

In the end, I found the following solution (starting off from this blog)

First, we need to collect up all of the names in our enumerated type.  We due this by using Reflection.

public static ObservableCollection<T> walkEnum<T>()
{
Type t = typeof(T);

var v = new ObservableCollection<T>() ;
// Retrieve the info for the type (it'd be nice to use Enum.GetNames here but alas, we're stuck with this)
FieldInfo[] infos;
infos = t.GetFields(BindingFlags.Public | BindingFlags.Static);

// Add each proper enum value to the collection
foreach (FieldInfo fi in infos)
{
v.Add((T)Enum.Parse(t, fi.Name, true));
}

return v;
}


The static method above returns an observable collection of all of the individual public named values in an enumerated type, by walking over the fields, getting the name, and then parsing the name back into the enumerated type itself.


Next we need to define our editing template in our DataGrid.


<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Instrument, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource Sections}}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>


The key here is the binding to a StaticResource.  I initially tried to bind to a property of an element name, but because this is in a data template, the LogicalTree is yet available, and the element fails to bind.


Finally, there’s the matter of setting the static resource.  Rather than create a new object so I could construct it in XAML, I decided it would be better to dynamically add the object to the StaticResources in the code behind.  Here’s how I did it:


First, we define our enum.


[DataContract(Name = "Section", Namespace = "YourNamespaceHere")]
public enum Section
{
[EnumMember] Conductor = 1,
[EnumMember] Soprano,
[EnumMember] TuttiCornets,
[EnumMember] RepianoCornets
// ...
}






Notice that the enum starts with 1.  That’s something else I found out along the way on this project.  MySQL database enums reserve 0 as an undefined value, but that will have to wait for another blog entry.


Next, we need to create our collection to be used as the ItemsSource as the first line of our objects constructor.


this.Resources.Add("Sections", walkEnum<Section>());

 

And there you have it.  A combo box bound to enums in a Silverlight 4 DataGrid.

No comments:

Post a Comment