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.
If you haven’t already, you can download the binaries and source for the DataGrid v1 here.
DataGridComboBoxColumn is a column that deserves some special attention. What makes it a little unique is how it hooks up to a source list of items and how the current SelectedItem maps back to the data source. Recall from my previous post on DataGridColumns, you will generally set the DataFieldBinding to map a property of the data source to the cells of a column,
Also recall that each column type has a separate UIElement when in an editing and non-editing state. For a DataGridTextColumn, it generates a TextBlock for non-editing and TextBox for editing. When each is generated the DataFieldBinding is mapped to the UIElement. No problems. For a DataGridComboBoxColumn, the default template for a non-editing state is a TextBlock and the default template for an editing state is a ComboBox. Mapping the DataFieldBinding to the TextBlock works but will not work so easily with the ComboBox as it’s an ItemsControl that is defined by a list and not a single object. With that in mind, some special APIs were introduced to DataGridComboBoxColumn.
These are the two public APIs specific to DataGridComboBoxColumn:
ItemsSource, which is pretty straightforward, is the ItemsSource set on the generated ComboBox for an editing state. DataFieldTarget does two things. First, it represents the selection value from the ComboBox. This value can be the ComboBox.SelectedItem, ComboBox.SelectedValue, or ComboBox.Text. Second, it is the mapping between the DataFieldBinding and the ComboBox. It is in this second part that allows you to update the ComboBox’s SelectedItem and changes will reflect back to the DataGrid’s data source.
Using the Northwind Database as an example (I’ve also included instructions in the sample), let’s say I want to display an editable Orders table and for the CustomerID foreign key column, I want to display a drop down list of possible choices. The choices will be all the CustomerID values from the Customer table. For the implementation, I’m going to auto-generate the columns so I can also show an example of how to customize columns when they are auto-generated.
Here is how I am populating the DataGrid with the Orders table:
I have a separate utility class to retrieve the DataSet which I call DBAccess. Then I get the DataTable and set the default view to the DataGrid. This will trigger the DataGridColumns to be auto-generated. For auto-generated columns you have access to two events, AutoGeneratingColumn and AutoGeneratedColumns, where you can customize the behavior of the columns. In my case I want to create a DataGridComboBoxColumn for the CustomerID field of the Orders table. Here is a possible implementation:
I set the DataFieldBinding to the CustomerID as that is the value that I want to represent in each cell of that column. I set the column.ItemsSource to the Customers table. Each item in the ComboBox.ItemsSource represents a record in the Customers table but I really just want to show is its CustomerID. I can do this by setting its SelectedValuePath and ItemTemplate to CustomerID which I do in the CustomerFKStyle. Remember that a DataGridComboBoxColumn generates a ComboBox only in the editing state so I have to set this style on column.EditingElementStyle. Lastly, I set column.DataFieldTarget to SelectedValue as this is value that will update the CustomerID property of my Orders table.
You can check out the full sample here. Note: I didn’t write the code to persist changes back to the database.
Also check out, WPF DataGrid: Working with DataGridComboBoxColumn (Part 2) for more info on DataGridComboBoxColumns.
More Related Material: