21
Vote

WPF DataGrid: DataGridComboBoxColumn.ItemsSource doesn't work

description

I'm trying to figure out how to get the DataGridComboBoxColumn.ItemsSource property working, well actually the DataGridComboBoxColumn in general.
I can build the behavior I want in a custom DataGridTemplateColumn but it never works with the DataGridComboBoxColumn.
 
A code sample is attached (simple WPF project) but I'll try to explain it.
 
Two simple entity classes:
public class Person
{
    public string Name { get; set; }
    public Country Country { get; set; }
}
 
public class Country
{
    public string Name { get; set; }
}
 
A simple Data class (this is the easiest way to simulate my problem, not the actual code :) )
public class Data
{
    public List<Person> Persons { get; set; }
    public List<Country> Countries { get; set; }
}
 
And in the Window's constructor:
        var data = new Data();
        data.Countries = new List<Country> { new Country { Name = "Belgium" }, new Country { Name = "USA" } };
        data.Persons = new List<Person> { new Person { Name = "Steve", Country = data.Countries[0] }, new Person { Name = "Bill Gates", Country = data.Countries[1] } };
        DataContext = data;
 
So what I want to do is show a list of persons, and bind the combobox for county to my Countries property, the working one with DataGridTemplateColumn is the following:
            <toolkit:DataGridTemplateColumn Header="Country">
                <toolkit:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Country.Name}" />
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellTemplate>
                <toolkit:DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox SelectedItem="{Binding Country}" DisplayMemberPath="Name" ItemsSource="{Binding DataContext.Countries, RelativeSource={RelativeSource AncestorType={x:Type Window}}, IsAsync=true}" />
                    </DataTemplate>
                </toolkit:DataGridTemplateColumn.CellEditingTemplate>
            </toolkit:DataGridTemplateColumn>
        </toolkit:DataGrid.Columns>
 
So I tried to use the same bindings for the DataGridComboBoxColumn as following:
            <toolkit:DataGridComboBoxColumn Header="Country" SelectedItemBinding="{Binding Country}" DisplayMemberPath="Name" ItemsSource="{Binding DataContext.Countries, RelativeSource={RelativeSource AncestorType={x:Type Window}}, IsAsync=true}" />
 
But nothing happens, the columns are empty and the combobox stays empty in editing mode.

file attachments

comments

XIU wrote Nov 20, 2008 at 11:25 AM

Forgot to mention the errors in output window are:

System.Windows.Data Error: 39 : BindingExpression path error: 'Country' property not found on 'object' ''Object' (HashCode=2902278)'. BindingExpression:Path=Country; DataItem='Object' (HashCode=2902278); target element is 'TextBlockComboBox' (Name=''); target property is 'SelectedItem' (type 'Object')
System.Windows.Data Error: 39 : BindingExpression path error: 'Name' property not found on 'object' ''Object' (HashCode=2902278)'. BindingExpression:Path=Name; DataItem='Object' (HashCode=2902278); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 39 : BindingExpression path error: 'Country' property not found on 'object' ''Object' (HashCode=2902278)'. BindingExpression:Path=Country.Name; DataItem='Object' (HashCode=2902278); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.Countries; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=50510248); target property is 'ItemsSource' (type 'IEnumerable')

XIU wrote Dec 9, 2008 at 10:43 AM

I managed to fix this problem by changing the default behavior for the ItemsSource property.
Inherit from DataGridComboBoxColumn, override GenerateEditingElement and GenerateElement.
When you have the generated element just copy the binding instead of trying to get the value.

VB Code:
Public Class DataGridComboBoxColumnEx
    Inherits DataGridComboBoxColumn

    Protected Overrides Function GenerateEditingElement(ByVal cell As Microsoft.Windows.Controls.DataGridCell, ByVal dataItem As Object) As System.Windows.FrameworkElement
        Dim element = MyBase.GenerateEditingElement(cell, dataItem)
        CopyItemsSource(element)
        Return element
    End Function

    Protected Overrides Function GenerateElement(ByVal cell As Microsoft.Windows.Controls.DataGridCell, ByVal dataItem As Object) As System.Windows.FrameworkElement
        Dim element = MyBase.GenerateElement(cell, dataItem)
        CopyItemsSource(element)
        Return element
    End Function

    Private Sub CopyItemsSource(ByVal element As FrameworkElement)
        BindingOperations.SetBinding(element, ComboBox.ItemsSourceProperty, BindingOperations.GetBinding(Me, ComboBox.ItemsSourceProperty))
    End Sub

End Class
In short (C#):
BindingOperations.SetBinding(element, ComboBox.ItemsSourceProperty, BindingOperations.GetBinding(this, ComboBox.ItemsSourceProperty));

wrote Feb 18, 2009 at 1:56 PM

jdmorrison wrote Feb 18, 2009 at 1:58 PM

Thanks for this solution, much appreciated. I wrote a detailed example of how to use this in my blog here http://joemorrison.org/blog/2009/02/17/excedrin-headache-35401281-using-combo-boxes-with-the-wpf-datagrid/ .

SamanthaMSFT wrote Feb 19, 2009 at 12:40 AM

The issue is that Bindings rely on the DataContext to inherit to the object on which it is set. This works naturally for elements in a visual tree and through special work for a few properties. The Columns collection needs this work done in order for Bindings like the one you specified to work. We have filed a bug in our internal database to be fixed in a future release.

Thanks!
Samantha

wrote Feb 19, 2009 at 12:41 AM

wrote Mar 6, 2009 at 10:36 PM

wrote Mar 9, 2009 at 9:59 AM

wrote May 6, 2009 at 1:40 PM

wrote Jun 4, 2009 at 11:37 AM

wrote Jun 19, 2009 at 8:19 PM

wrote Jun 24, 2009 at 10:58 AM

wrote Jun 25, 2009 at 1:02 PM

wrote Jul 30, 2009 at 11:31 AM

wrote Sep 4, 2009 at 9:48 AM

wrote Sep 9, 2009 at 2:39 PM

wrote Nov 18, 2009 at 5:38 PM

wrote Mar 16, 2011 at 2:55 PM

wrote Aug 16, 2011 at 9:29 AM

wrote Sep 22, 2011 at 1:37 PM

wrote Jan 6, 2012 at 4:24 PM

wrote Feb 22, 2013 at 1:41 AM

wrote Apr 23, 2013 at 11:50 PM

wrote Jan 2, 2014 at 12:56 PM

wst wrote Jan 2, 2014 at 12:57 PM

Please fix this, very annoying!

wst wrote Jan 2, 2014 at 1:12 PM

This solution worked for me by setting the elementstyle and the editingelementstyle:
http://stackoverflow.com/a/5409984/187650

wrote Aug 6, 2014 at 7:07 AM

wrote Oct 10, 2015 at 7:53 PM