Most recommendations for binding complex objects in Silverlight involve converters. This works great, but I find creating another class and keeping track of it to be a nuisance.
To understand the problem, consider an
ObservableCollection<customer>
where the
Customer
has a
CustomerType
object that we want to handle in a
ComboBox
. The
Customer
class looks like:
public class Customer
{
public int ID { get;set;}
public string Name { get;set;}
public CustomerType Type { get;set;}
}
public class CustomerType
{
public int ID { get;set;}
public string Name { get;set;}
}
Now, if I send a list of
Customers
to a
DataGrid
in Silverlight (I am using a
DomainDataSource
, but it doesn't matter), I will not succeed with something like this:
<sdk:DataGridTemplateColumn x:Name="customerType" Header="Type">
(sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Data, ElementName=customerDomainDataSource}"
SelectedValue="{Binding Path=Type, Mode=TwoWay}"
DisplayMemberPath="Name"
SelectedValuePath="ID" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
Since
DomainDataSource
produces a partial class for
Customer
, just as does WCF, I add this extension to my
CustomerClass
:
public partial class Customer
{
public static ObservableCollection<customertype> Types { get;set;}
public int CustomerTypeID
{
get
{
return Type.ID;
}
set
{
Type = Types.FirstOrDefault(t => t.ID == value);
}
}
}
Notice that we have to have the Types available somehow. I simply grab the list from the
ComboBox.ItemsSource
when it becomes available (asynchronous, remember) and put it into my
Customer.Types
list (
static
so I don't have to do it for every
Customer
).
Now, I change the line above to:
SelectedValue="{Binding Path=CustomerTypeID, Mode=TwoWay}"
Now, my
ComboBox
works perfectly.
By the way, the reason that the alternate approach doesn't work is not immediately obvious, but it is caused by the fact that the object comparison of the
CustomerType
list in the combo with the
Customer.Type
because they are not the same object. They have the same ID, but we have to force them to compare by ID.
I prefer this because it is immediately obvious where the conversion is taking place, and I don't have to track yet another class that I forget to use the next time I need a
CustomerType listbox
or
combobox
.