Welcome to MSDN Blogs Sign in | Join | Help

Vincent Sibal's Blog

WPF Programming Topics
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.

Posted: Friday, October 31, 2008 7:49 AM by vinsibal
Attachment(s): DataGrid_V1_ComboBoxColumnSamples.zip

Comments

Vincent Sibal's Blog said:

UPDATE: DataGridComboBoxColumn has been updated from CTP to V1. See the post here for the updates to

# October 31, 2008 10:56 AM

Vincent Sibal's Blog said:

UPDATE: DataGridComboBoxColumn has been updated from CTP to V1. See the post here for the updates to

# October 31, 2008 11:00 AM

Ruler said:

How do i get the values selected by user inside the datagrid?

with the normal combobox i can do

comboname.SelectedValue

# November 3, 2008 1:02 AM

regev said:

how do you handle with copy-paste in DataGridComboBoxColumn?

# November 3, 2008 6:56 AM

vinsibal said:

Ruler,

You can get the selected rows through DataGrid.SelectedItems and you can get the selected cells through DataGrid.SelectedCells.

# November 3, 2008 8:36 AM

vinsibal said:

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?

# November 3, 2008 8:37 AM

Peter said:

Great stuff! Much better than some of the hoops you had to jump through with the CTP. Thanks!

# November 3, 2008 3:35 PM

Sachet said:

Can you please tell me how i can add autocomplete and autosuggest feature to the DataGridComboBoxColumn?

# November 5, 2008 8:29 AM

vinsibal said:

Sachet,

Try setting the EditingElementStyle in a DataGridComboBoxColumn,

<dg:DataGridComboBoxColumn.EditingElementStyle>

                       <Style TargetType="ComboBox">

                           <Setter Property="IsEditable" Value="True" />

                       </Style>                    

</dg:DataGridComboBoxColumn.EditingElementStyle>

# November 5, 2008 8:56 AM

Sachet said:

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;

                }

            };

       };

   }

};

# November 5, 2008 10:11 AM

vinsibal said:

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.

# November 5, 2008 10:47 AM

Sachet said:

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 you

# November 5, 2008 11:21 AM

vinsibal said:

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.

# November 5, 2008 5:23 PM

Sachet said:

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.

# November 6, 2008 2:34 PM

Sachet said:

Actually what i wanted to do is that I need a datagrid which would have initially only one blank row, the user should be able to add as many entries as he wishes. The datagrid consists of two columns, a combobox column and a Text box column. The combobox consists of a large no of items hence autosuggest, like the one seen in the Windows "Run" Dialog Window is required.

Is this possible to be done with the datagrid or would i have to search for other controls like the ListView or maybe create a custom control???

Thanks

# November 6, 2008 2:38 PM

vinsibal said:

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;

                       };

                   };

           }

       }

# November 6, 2008 3:00 PM

Sachet said:

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?

thanks

# November 6, 2008 4:29 PM

BRanck said:

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.

# November 17, 2008 8:57 PM

Senthil said:

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.

# December 6, 2008 12:02 AM

vinsibal said:

# December 17, 2008 12:21 PM

Windows Presentation Foundation SDK said:

Here’s another DataGrid sample using the WPF Toolkit .&#160; It includes Creating templates for DataGridTemplateColumn

# April 2, 2009 5:39 PM

Neo said:

Is there a way to dynamically set the value for a SelectedIndex in Datagrid tag? Txs

<dg:DataGrid SelectedIndex=""

# April 25, 2009 3:31 PM

vinsibal said:

Neo,

Try setting up a data binding.

<dg:DataGrid SelectedIndex="{Binding Path=<some property>}"

# April 28, 2009 8:24 AM

Peter said:

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,

Peter

# April 30, 2009 1:00 PM

vinsibal said:

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.

# May 2, 2009 10:39 AM

Ramesh said:

hi,

i have datagride inside combo that combo did't binding anybody help me

Advance wishes

# June 26, 2009 1:38 AM

Mike Graham said:

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 :)

# September 16, 2009 10:39 AM

Md Rasool said:

plz tell me how to select the iten present in comboboxcolumn wpf datagrid

# September 23, 2009 2:49 AM

Bhargav Joshi said:

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! Thanks

# October 19, 2009 10:44 AM

Frank said:

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?

# October 27, 2009 12:21 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker