Another DataBinding for a DataGridComboBoxColumn Question.

Nov 9, 2008 at 10:31 PM
Edited Nov 9, 2008 at 10:32 PM
I've been fighting with trying to get databinding working on a DataGridComboBoxColumn all morning.  So far none of it seems to work.  I just get an empty column.  It's probably just something brain dead on my part.  But maybe someone could take a peek and see what I'm doing wrong.

I made a sample project to simplify the problem.

XAML:
 
<
Window x:Class="WpfApplication2.Window1"
  xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
  xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
  xmlns:tk="http://schemas.microsoft.com/wpf/2008/toolkit"
  Title="Window1" Height="300" Width="300"
  Name="MyWindow">
  <Grid>
    <tk:DataGrid ItemsSource="{Binding Path=Orders, ElementName=MyWindow}"
                          AutoGenerateColumns="False" CanUserAddRows="False" >
      <tk:DataGrid.Columns>
        <tk:DataGridTextColumn Header="ID" Width="60"
                                                 Binding="{Binding Path=ID}"
                                                 IsReadOnly="True"/>
        <tk:DataGridTextColumn Header="Description" Width="90"
                                                 Binding="{Binding Path=Description}"
                                                 IsReadOnly="True"/>
        <tk:DataGridComboBoxColumn SelectedValueBinding="{Binding Path=Customer}"
                                                           SelectedValuePath="Customer"
                                                           DisplayMemberPath="Customer.Name"
                                                           Header="Customer" 
                                                           ItemsSource="{Binding Path=Customers, ElementName=MyWindow}"/> 
 
     </tk:DataGrid.Columns>
    </tk:DataGrid>
  </Grid>
</
Window>

 

 

C#

using System.Windows;
using System.Collections.ObjectModel;

namespace
WpfApplication2
  {
  public class Customer
    {
    public int ID { get; set; }
    public string Name { get; set; }
    }

 

 

 

  public class Order
    {
    public int ID { get; set; }
    public Customer Customer { get; set; }
    public string Description { get; set; }
    }

 

 

 

  public partial class Window1 : Window
    {
    public ObservableCollection<Order> Orders { get; set; }
    public ObservableCollection<Customer> Customers { get; set; }

    public Window1()
      {
      Customers =
new ObservableCollection<Customer>();
      Customer c = new Customer();
      c.ID = 1;
      c.Name =
"Bill";
      Customers.Add(c);
      c =
new Customer();
      c.ID = 2; 
      c.Name =
"Jane"
      Customers.Add(c);
      c =
new Customer(); 
      c.ID = 3;
      c.Name =
"Sam"
      Customers.Add(c);
      c.ID = 4;
      c.Name =
"Fred"
      Customers.Add(c);
      Orders =
new ObservableCollection<Order>(); 
      Order o = new Order(); 
      o.ID = 1;
      o.Customer = Customers[0];
      o.Description =
"Test Order 1"
      Orders.Add(o);
      o =
new Order(); 
      o.ID = 1;
      o.Customer = Customers[1];
      o.Description =
"Test Order 2"
      Orders.Add(o);

 

 

 

      InitializeComponent();
      }
    }
  }

End of code

ItemsSource="{Binding Path=Customers, ElementName=MyWindow}"

 

 

Does throw this error, not sure why.

//System.Windows.Data Error: 2 :
//Cannot find governing FrameworkElement or FrameworkContentElement for target element.
//BindingExpression:Path=Customers; DataItem=null; target element is 'DataGridComboBoxColumn'
//(HashCode=42659827); target property is 'ItemsSource' (type 'IEnumerable')

 

Thanks for any assistance you can offer.

John
Coordinator
Nov 10, 2008 at 12:27 PM
 The Data error that you see is the issue.  DataGridColumns will not be able to find FE's or FCE's from Window b/c they are not part of the tree.  I suggest setting the ItemsSource as a StaticResource of Customers instead or setting it in code.
Nov 10, 2008 at 6:37 PM
I kept googling even after after I posted this, I never did find a solution.  I found the question many times, but no answer.  I had however observed that every time I saw a combo box a static resource was being used to fill it and was afraid that that was going to be the answer.

I'm still kind of new at this and have never used static data resources because most of my data requires dynamic updating.  The drop down list that I am creating can change after the datagrid has been initialized, based on a selection elsewhere on the page.

So I guess I need to dig in and learn how to update static resources.  Hopefully it turns out to be something easy and I go duh, why haven't I been doing it that way all along. :-)
Nov 10, 2008 at 7:44 PM
OK I've solved the problem.

I added a class:

 

public class DropList : ObservableCollection<Customer>
  {
  }

Then filled it after the InitializeComponent():

 

 

ObjectDataProvider oDP = (ObjectDataProvider)this.FindResource("oDropList");
if (oDP != null)
  {
  using (oDP.DeferRefresh())
    {
    DropList l = (DropList)oDP.Data;
    l.Add(Customers[0]);
    l.Add(Customers[1]);
    }
  }

 

 

 

I added this to the XAML:

<
Window.Resources>
  <ObjectDataProvider ObjectType="{x:Type local:DropList}" x:Key="oDropList" />
</Window.Resources>

 

 

 

 

And changed my bindings to:

<tk:DataGridComboBoxColumn SelectedItemBinding="{Binding Path=Customer}"
                                                   DisplayMemberPath="Name"
                                                   Header="Customer"
                                                   TextBinding="{Binding Path=Customer.Name}"
                                                   ItemsSource="{Binding Source={StaticResource oDropList}}" />

 

 

 

I am now able to dynamically refresh the drop down list.  By the way, the sample classes here were laid out to be similar to Linq relational data query results, so this should work with that type of data.  Hopefully this solution helps someone else someday.  :-)

John