DataGrid with data binding doesn't update the binding source

Oct 15, 2008 at 11:46 AM
Hi!

I'm iterating over a C# object's property list with C#, and am filling up a Grid column with a Label in the first column, and an editing control appropriate to the property in the second column.  The editing control gets a TwoWay data binding to the object's property. 

The idea have been to use a WPF DataGrid for properties that are List<something>.

On my test source object I have an IList<SillyClassWithOneField> property (where SillyClassWithOneField is a class with a single string property).

The DataGrid is created with a data binding to the list property, and shows up with the list values.  This is the code that creates the DataGrid control:
   DataGrid datagrid = new DataGrid();
   datagrid.VerticalAlignment =
VerticalAlignment.Stretch;
   Binding binding =  new Binding(propertyName)
   {
      Source = sourceObj,
      Mode =
BindingMode.TwoWay,
      UpdateSourceTrigger =
UpdateSourceTrigger.PropertyChanged
   };
   datagrid.SetBinding(ItemsControl.ItemsSourceProperty, binding);
   control = datagrid;

As said, the list values show up, but adding to the DataGrid or modifying existing values in the DataGrid does not cause the list in the source property to be changed.

Does anyone know how to fix this?  Am I lacking some magic in the binding setup?

Thanx!
Oct 15, 2008 at 1:13 PM
Could the reason no update takes place, be that I'm binding to the ItemsSource property?  Ie. something that's only used as a source, but not updated when the value changes?
Coordinator
Oct 15, 2008 at 1:26 PM
What do your DataGridColumn definitions look like?  Also, how are you defining your data source?
Oct 15, 2008 at 2:07 PM
I have no DataGridColumn definitions, so I guess I'm running with whatever are the defaults.  I still haven't figured out how to define DataGridColumns and their templates in C# code.  All the examples I can find, in books and on the net, are in XAML.  I have tried to create columns programatically, but I can't figure out where to set the binding, and what the bindings should bind to (in the case of a List<string> property, should I bind to the source object and the property?  But in the case of a List<SomeClass>, what should the binding for a column be to?)

The data source is a C# class with properties.  To complicate things, we inject a proxy object between the data source.  This proxy object implements the INotifyPropertyChanged interface, wraps the original source, has the same property setters and getters, with the setters calculating whether a property has been changed, and sends an event notifying listeners, if a property has been found to have changed its value. 

The reason for the proxy is that the owners of the base class don't want to introduce dependencies to the INotifyPropertyChanged interface.

The original data source in my test case is defined like this (in a slightly anonymized version, with class and property xml-doc comments removed, and with indentation messed up because of the pasting into this forum (I have hand-reindented after pasting)):

 

public class MockObject : SomeBaseClass
{
   public string AString { get; set; }
   public char? ANullableChar { get; set; }
   public char? ANullableCharWithSuggestedValues { get; set; }
   public bool ABool { get; set; }
   public int AnInt { get; set; }
   public MockEnum? ANullableEnum { get; set; }
   public MockEnum AnEnum { get; set; }

 

 

   private readonly IList<string> aListOfStrings = new List<string>();
   public IList<string> AListOfStrings
   {
     
get { return aListOfStrings; }
     
set
      {
         aListOfStrings.Clear();
         foreach(string s in value)
         {
            aListOfStrings.Add(s);
         }
      }
   }

 

   public class SillyClassWithOneField
   {
       public string AStringValueThatBecomesTheColumnHeader { get; set; }
    }

    private readonly IList<SillyClassWithOneField> aListOfStructs = new List<SillyClassWithOneField>();
    public IList<SillyClassWithOneField> AListOfStucts
    {
         get { return aListOfStructs; }
         set
         {
             aListOfStrings.Clear();
              foreach (SillyClassWithOneField s in value)
              {
                   aListOfStructs.Add(s);
               }
           }
      }
}

Oct 15, 2008 at 5:06 PM
Edited Oct 15, 2008 at 5:07 PM
> I'm iterating over a C# object's property list with C#, and am filling up a Grid column with a Label in the first column, and an editing
> control appropriate to the property in the second column.  The editing control gets a TwoWay data binding to the object's property. 

I guess this is similar to what you (vinsibal) does here:
 http://blogs.msdn.com/vinsibal/archive/2008/05/27/using-ieditablecollectionview-with-dynamically-generated-gridviewcolumns.aspx

But I'd like to go down one step further, and handle the properties that are lists of something.  Primarily lists of strings, but also lists of instances of classes consisting of public properties.

And that's where it breaks down for me...
Oct 15, 2008 at 5:33 PM
>> I'm iterating over a C# object's property list with C#, and am filling up a Grid column with a Label in the first column, and an editing
>> control appropriate to the property in the second column.  The editing control gets a TwoWay data binding to the object's property. 

> I guess this is similar to what you (vinsibal) does here:
>  http://blogs.msdn.com/vinsibal/archive/2008/05/27/using-ieditablecollectionview-with-dynamically-generated-gridviewcolumns.aspx

No it's not..  It's actually very close to what I'm trying to accomplish.

What you do here is build up columns (while I am building rows), and for each column you create a FrameworkElementFactory and a Binding, and set the Binding on the FrameworkElementFactory.  You also create a DataTemplate that gets the FrameworkElementFactory, and then the column gets the template.

This sounds a lot like what happens when I call DataGrid.SetBinding.(ItemsControl.ItemsSourceProperty, binding); where binding is bound to a source object property that is a list of instances of a class with properties...?

One problem here is that the FrameworkElementFactory and friends seems to be deprecated.

Another problem here is that I don't understand how the binding on the template factory maps down to binding to the collection members.