UPDATE: DataGridComboBoxColumn has been updated from CTP to V1. See the post here for the updates to the DataGridComboBoxColumn as well as an updated sample.
One solution could be using a converter on the DataFieldBinding to transform the CustomerID to some other alias. Remember though in our example, the overall table (Orders) that the DataGrid is displaying is different that the table that the ComboBox is using (Customers). So in your converter you may need to optimize the calls to get the Customer table. I have excluded that from the example as that is a separate topic of discussion.
<dg:DataGridComboBoxColumn
DataFieldBinding="{Binding CustomerID,
Converter={StaticResource CustomerConverter},
ConverterParameter=ContactName}"
ItemsSource="{Binding Source={StaticResource customerDataProvider}}"
Header="CustomerID (ContactName alias)"
DataFieldTarget="Text">
<dg:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="SelectedValuePath" Value="CustomerID" />
<Setter Property="DisplayMemberPath" Value="ContactName" />
</Style>
</dg:DataGridComboBoxColumn.EditingElementStyle>
</dg:DataGridComboBoxColumn>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string customerID = (string)value;
DataTable dataTable = DBAccess.GetCustomers().Tables["Customers"];
foreach (DataRow row in dataTable.Rows)
if (row["CustomerID"].ToString() == customerID)
return row[parameter.ToString()];
}
return null;
The converter is returning a string value and remember that the DataFieldTarget is what maps the ComboBox value back to the DataFieldBinding, so I have set the DataFieldTarget to “Text”. Also, as the DisplayMemberPath and ConverterParameter show, I am using the ContactName as the alias.
Another solution which is very similar to the first one is to use the converter as I did above but with a DataGridTemplateColumn. There really isn’t a big advantage going with a DataGridTemplateColumn over a DataGridComboBoxColumn in this particular example, but it does give you more flexibility on the type of element to display in the non-editing state. Anyway, here is an example:
<dg:DataGridTemplateColumn Header="CustomerID (ContactName alias)">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=CustomerID, Mode=OneWay, Converter={StaticResource CustomerConverter}, ConverterParameter=ContactName}" />
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
<dg:DataGridTemplateColumn.CellEditingTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource customerDataProvider}}"
SelectedValue="{Binding CustomerID}" SelectedValuePath="CustomerID" DisplayMemberPath="ContactName" />
</dg:DataGridTemplateColumn.CellEditingTemplate>
</dg:DataGridTemplateColumn>
One thing to note about this example is what is bound to what. In CellTemplate, the TextBlock is using DataGrid’s DataContext and is bound to the CustoemrID field of the Orders table. In CellEditingTemplate, the ComboBox is using the Customer table as the Source for the ItemsSource but the DataContext is still the DataGrid for everything elese. That means that SelectedValue’s binding to CustomerID is based on the CustomerID of the Orders table and that binding is the one that will update the source.
A third and a little more time consuming approach would be to subclass DataGridComboBoxColumn and add a property for the display. If you take a look at the DataGridHyperlinkColumn it actually has a special API for something like this which is ContentBinding. ContentBinding maps the content it is bound to what gets displayed as the link in the cells of that column. However, there is still a DataFieldBinding which maps to the actual hyperlink that it represents.
Here is a sample for the first two solutions.