WPF DataGrid - DataGridComboBoxColumn v1 Intro
Intro
If you haven't already, you can download the DataGrid v1 bits and source here. DataGridComboBoxColumn has had a make-over since the CTP release. In particular, the whole data binding story has been updated so that you can accomplish basic ComboBox tasks that before required some tedious workarounds. While other stock columns such as DataGridTextColumn and DataGridCheckBoxColumn use Binding for the visual to data hook up, DataGridComboBoxColumn uses a different route with three possible ways to hook up a binding. Here are the APIs that are specific to the DataGridComboBoxColumn:
public class DataGridComboBoxColumn : DataGridColumn
{
public string DisplayMemberPath { get; set; }
public IEnumerable ItemsSource { get; set; }
public virtual BindingBase SelectedItemBinding { get; set; }
public virtual BindingBase SelectedValueBinding { get; set; }
public string SelectedValuePath { get; set; }
public virtual BindingBase TextBinding { get; set; }
}
The three mechanisms to hook up the binding are:
· SelectedItemBinding
· SelectedValueBinding
· TextBinding
These three bindings basically map to the cell’s content being bound to ComboBox.SelectedItem, ComboBox.SelectedValue, or ComboBox.Text respectively. SelectedValuePath and DisplayMemberPath are convenience methods on a ComboBox control and apply to ComboBox.SelectedValuePath and ComboBox.DisplayMemberBinding respectively. Overall, you can think of these APIs as convenience methods that apply to the ComboBox element of the cell. Let’s go through some use cases.
Some examples
When the column is bound to a primitive data type such as int, string, or bool, and you want the ComboBox to have a list of similar items to choose from, you can use SelectedItemBinding like so:
<dg:DataGridComboBoxColumn SelectedItemBinding="{Binding ShipCity}">
<dg:DataGridComboBoxColumn.ItemsSource>
<col:ArrayList>
<sys:String>Redmond</sys:String>
<sys:String>Bellevue</sys:String>
<sys:String>Seattle</sys:String>
<sys:String>Renton</sys:String>
</col:ArrayList>
</dg:DataGridComboBoxColumn.ItemsSource>
</dg:DataGridComboBoxColumn>
ShipCity is a string type so the ComboBox.SelectedItem maps correctly to the item in the DataGrid’s column.
Let’s say I have a foreign key relationship between an Orders table and a Customers table. Orders contains a CustomerID foreign key and will be the ItemsSource for the DataGrid. I can setup a DataGridComboBoxColumn with Customers being its ItemsSource and hooking up the SelectedValueBinding like so:
<dg:DataGridComboBoxColumn SelectedValueBinding="{Binding CustomerID}"
SelectedValuePath="CustomerID"
DisplayMemberPath="ContactName"
Header="CustomerID (ContactName alias using SelectedValueBinding)"
ItemsSource="{Binding Source={StaticResource customerDataProvider}}">
SelectedValueBinding maps to Orders’ CustomerID, which also maps to Customers’ CustomerID through SelectedValuePath. I use DisplayMemberPath to alias the CustomerID with a more user friendly value to the end user.
You can download the solution to these examples here.
DataGrid_V1_ComboBoxColumnSamples.zip
Comments
Anonymous
October 31, 2008
UPDATE: DataGridComboBoxColumn has been updated from CTP to V1. See the post here for the updates toAnonymous
October 31, 2008
UPDATE: DataGridComboBoxColumn has been updated from CTP to V1. See the post here for the updates toAnonymous
November 02, 2008
How do i get the values selected by user inside the datagrid? with the normal combobox i can do comboname.SelectedValueAnonymous
November 02, 2008
how do you handle with copy-paste in DataGridComboBoxColumn?Anonymous
November 03, 2008
Ruler, You can get the selected rows through DataGrid.SelectedItems and you can get the selected cells through DataGrid.SelectedCells.Anonymous
November 03, 2008
regev, The paste sample here, http://blogs.msdn.com/vinsibal/archive/2008/09/19/wpf-datagrid-clipboard-paste-sample.aspx, does not meet your requirements?Anonymous
November 03, 2008
Great stuff! Much better than some of the hoops you had to jump through with the CTP. Thanks!Anonymous
November 05, 2008
Can you please tell me how i can add autocomplete and autosuggest feature to the DataGridComboBoxColumn?Anonymous
November 05, 2008
Sachet, Try setting the EditingElementStyle in a DataGridComboBoxColumn, <dg:DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="IsEditable" Value="True" /> </Style> </dg:DataGridComboBoxColumn.EditingElementStyle>Anonymous
November 05, 2008
when i set the editing element style in DataGridComboBoxColumn, it only enable me to be able to type in to the combobox, it does not filter the items in the combobox to display only the items matching the text being typed... I have been able to get this done in a regular combobox using the code shown below. Could you please help me as to how i can get the same feature here in the DataGridComboBoxColumn, possibly by modifying the code below? Thank you. myComboBox.ItemsSource = myItemsList; myComboBox.IsEditable = true; myComboBox.IsTextSearchEnabled = false; myComboBox.Loaded += delegate { TextBox textBox = myComboBox.Template.FindName("PART_EditableTextBox", myComboBox) as TextBox; Popup popup = myComboBox.Template.FindName("PART_Popup", myComboBox) as Popup; if (textBox != null) { textBox.TextChanged += delegate { popup.IsOpen = true; myComboBox.Items.Filter += a => { myItems selectedItem = (myItems)a; if (a.ToString().Contains(textBox.Text)) { return true; } else { return false; } }; }; } };Anonymous
November 05, 2008
Sachet, From the sample on this post, I was able to update the EditingElementStyle of the ComboBoxColumn and get the autocomplete support without having to write my own filter. Maybe it's something you are doing in your DataGridComboBoxColumn. I suggest trying the sample on this post and diff'ing it with your implementation of DataGridComboBoxColumn.Anonymous
November 05, 2008
Thank you for replying so quickly, i have already downloaded your sample application. I even set the IsEditable property to true. But the problem is still the same, i.e. when i enter the text in to the combobox column the visible items in the dropdown box remain the same, whereas in the autocomplete combobox normally a popup would appear showing only the set of items that match the text entered by us. If you could use the following code and run the application, maybe you could understand me more clearly, //--------------Window4.xaml------------- <Window x:Class="WpfApplication1.Window4" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:DotNetZen.AutoFilteredComboBox" Title="AutoCompleteComboBoxDemo" Height="300" Width="300"> <StackPanel> <ComboBox Height="30" Width="200" IsEditable="True" Name="comboBox"> <TextBlock>Item type 1</TextBlock> <TextBlock>Item type 2</TextBlock> <TextBlock>Object class 1</TextBlock> <TextBlock>New Method</TextBlock> </ComboBox> </StackPanel> </Window> //-------------------------------------- //---------Window4.xaml.cs-------------- using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; namespace WpfApplication1 { /// <summary> /// Interaction logic for Window4.xaml /// </summary> public partial class Window4 : Window { public Window4() { InitializeComponent(); comboBox.IsTextSearchEnabled = false; comboBox.Loaded += delegate { TextBox textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox; Popup popup = comboBox.Template.FindName("PART_Popup", comboBox) as Popup; if (textBox != null) { textBox.TextChanged += delegate { popup.IsOpen = true; comboBox.Items.Filter += a => { TextBlock b = (TextBlock)a; if (b.Text.Contains(textBox.Text)) { return true; } return false; }; }; } }; } } } //----------------------- I wanted to emulate the features in the combobox above in the DataGridComboBoxCloumn. Could you kindly look at it and help me? Thank youAnonymous
November 05, 2008
Sachet, I'm still looking into why it's not working for DataGridComboBoxColumn but I tested it out with DataGridTemplateColumn and it works just fine. For the time being give DataGridTemplateColumn a try if you are in a rush.Anonymous
November 06, 2008
Could you please give me the code of the autocomplete sample that you found to be working using DataGridTemplateColumn. I used the method shown in the following blog post that i found yesterday, http://www.dev102.com/2008/08/07/how-to-access-a-wpf-control-which-is-located-in-a-datatemplate/ It shows a method of accessing the Combobox that we define in the DataTemplate for DataGridTemplateColumn through code. Combining that method and the autocomplete combox sample that i showed above i was able to get autocomplete support. BUT now the problem is that when I type something into the combobox in any one row of the datagrid the dropdown boxes of the same combobox column in all rows open up at the same time. I need to find a way to reference the combobox in each row separately.Anonymous
November 06, 2008
The comment has been removedAnonymous
November 06, 2008
Sachet, Here is the code for the DataGridTemplateColumn support. Also, the scenario that you describe is doable with the DataGrid. <dg:DataGridTemplateColumn Header="Cake TemplateColumn" > <dg:DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Cake, Mode=OneWay}"/> </DataTemplate> </dg:DataGridTemplateColumn.CellTemplate> <dg:DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox IsEditable="True" IsTextSearchEnabled="False" Loaded="ComboBoxLoaded" SelectedItem="{Binding Path=Cake, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <ComboBox.ItemsSource> <col:ArrayList> <sys:String>Chocolate</sys:String> <sys:String>Vanilla</sys:String> <sys:String>Strawberry</sys:String> <sys:String>Cookie</sys:String> <sys:String>Pound Cake</sys:String> </col:ArrayList> </ComboBox.ItemsSource> </ComboBox> </DataTemplate> </dg:DataGridTemplateColumn.CellEditingTemplate> </dg:DataGridTemplateColumn> private void ComboBoxLoaded(object sender, RoutedEventArgs e) { ComboBox comboBox = sender as ComboBox; TextBox textBox = comboBox.Template.FindName("PART_EditableTextBox", comboBox) as TextBox; if (textBox != null) { textBox.TextChanged += (s, args) => { comboBox.IsDropDownOpen = true; comboBox.Items.Filter += a => { string value = (string)a; if (value.Contains(textBox.Text)) { return true; } return false; }; }; } }Anonymous
November 06, 2008
Hi, I tried the code you gave above... It is certainly giving Autosuggest feature but did you notice that when there are multiple rows of data in the datagrid, the value selected in the combobox of one particular row automatically becomes the selected value of comboboxes of all the rows... how is it possible to refer to the selected values of the combobox column of each row separately? thanksAnonymous
November 17, 2008
Hi Vince, I am loading the WPF datagrid V1 from a text File using a data adapter to read the file. Prior to loading I build a Schema.ini (that includes column header text and other column definitions) and save it next to the text file in its directory. This all works fine. However, once I am done with the text file, I need to load a different text file (with the same name) that now has new and different data. My problem is that I cannot figure out how to clear or reset the data grid. The new data loads just fine but the Headers are now repeated in the grid with a number 1 after each of the duplicate header names. If I do it a third time, I have yet another set of headers (and I presume columns) now with the column name and a 2. So could you point me to a way to Reset or Clear the WPF DataGrid, or perhaps remove the old columns prior to loading the second time? I would prefer to do it in VB code behind. I tried looping in the grids columns colection without success so far.Anonymous
December 05, 2008
I want to display hierarchical data in the datagrid. First column is Categorys datacombobox column and the second column is the subcategories datacombobox column. Based on the first selection column the second column combobox need to be populated. How to do this in the datagrid. I searched so many articals and somany websites regarding this issue. Still I am searching for this. Could u help me in this regard. Category table columns: id and name subcategorys table columns: id , name and cateogry_id I need to store in the table all the id values only. Please help.Anonymous
December 17, 2008
Senthil, I just wrote a new post that might help you out, http://msdn.technetweb3.orcsweb.com/vinsibal/archive/2008/12/17/wpf-datagrid-dynamically-updating-datagridcomboboxcolumn.aspx.Anonymous
April 02, 2009
Here’s another DataGrid sample using the WPF Toolkit .  It includes Creating templates for DataGridTemplateColumnAnonymous
April 25, 2009
Is there a way to dynamically set the value for a SelectedIndex in Datagrid tag? Txs <dg:DataGrid SelectedIndex=""Anonymous
April 28, 2009
Neo, Try setting up a data binding. <dg:DataGrid SelectedIndex="{Binding Path=<some property>}"Anonymous
April 30, 2009
Vincent, could you please give me a hint how I could use the text that is displayed in the DataGridComboBoxColumn inside the RowDetailsTemplate? As I only have an ID (int) at hand I would like to display the text in a TextBlock in the RowDetailsTemplate too. How can I bind them together? TIA, PeterAnonymous
May 02, 2009
Peter, I don't think you can bind the textblock in the RowDetailsTemplate to the ComboBox in the cell. Maybe you can do something similar like the ComboBox. Pass the RowDetailsTemplate the binding for the ID and the other data to show a different display value.Anonymous
June 25, 2009
hi, i have datagride inside combo that combo did't binding anybody help me Advance wishesAnonymous
September 16, 2009
Ha !! Figured it out :) I couldn't figure out why my code didn't work and yours did... Here it is if anyone else is interested... I was using this class for my list of items in the combo: public class ModeComboItem { public string SyncModeValue; public string SyncModeText; } but needed to be using this class instead !! public class ModeComboItem { public string SyncModeValue { get; set; } public string SyncModeText { get; set; } } small change... big improvement :)Anonymous
September 22, 2009
plz tell me how to select the iten present in comboboxcolumn wpf datagridAnonymous
October 19, 2009
I am trying to add a tooltip to a DataGridComboBoxColumn cell. I am able to display the tooltip in editing mode by setting EditingElementStyle. However, when I set the ElementStyle with target type TextBlock it throws an exception saying that the type TextBlock does not match TextBlockComboBox. Also, I am not able to find the type TextBlockComboBox as a public type in the toolkit. Please help! ThanksAnonymous
October 27, 2009
I am binding the DataContext of a DataGrid to a class that contains an ObservableCollection of properties in XAML. Then, I create each column programmatically in C# and bind them to each specific property. How can you make each row's DataGridComboBoxColumn ItemsSource bind to a different array?Anonymous
March 01, 2010
Hi Vince, How to reset or clear the contents of the datagrid? Also, at initialization, I need to display 4 empty rows which the user may subsequently populate with data. How to display empty rows in datagrid? Thanks,Anonymous
March 11, 2010
Santhosh, To clear content you can just clear your items source that the DataGrid is bound to. For adding four empty rows, you can add four items with default initialization.Anonymous
April 08, 2010
How can I create a combobox in a datagrid column in the C# code class through get-set property. I could manage to create check box in grid view column through get -set property code.(WPF) Like, the code below brings a check box on front end datagrid column at run time.And works well with the data integration too. public bool Enabled { get { if (this._sublocation.Enabled > 0) return true; else return false; } set { if (value == true && this._sublocation.Enabled < 1) this._sublocation.Enabled = 1; else if (value == false && this._sublocation.Enabled > 0) this._sublocation.Enabled = 0; else return; base.OnPropertyChanged("Enabled"); } }Anonymous
April 20, 2010
vinsibal, Why SelectedItems property is not a Dependency Property? How can I bind it to ViewModel? Do I have to create AttachedProperty for that? Thanks, Ivan