views:

473

answers:

2

I am struggling with the learning curve on WPF data binding and could use an example. Bonus points for those that answer the question and link to an article that helped them "get" WPF data binding.

I am trying to bind a custom Table object with a WPF DataGrid.

Here is my objects (I do not have the ability to change them, signatures truncated a bit):

public class MyTable
{
    public int ColumnCount { get; }
    public string GetColumnName(int columnIndex);
    public IEnumerable<MyTableRow> GetRows();
}

public class MyTableRow
{
    public MyTableCell [] Cells { get; }
}

public class MyTableCell
{
    public string Value { get; }
}

So the DataContext on the current Window is an instance of MyTable. I could not see any clear way to auto generate the columns from my MyTable object so I generated them in code:

private void dg_Table_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    MyTable tbl = e.NewValue as MyTable;

    if (tbl != null)
    {
        //setup data grid columns
        dg_Table.Columns.Clear();

        for (int i = 0; i < tbl.ColumnCount; i++)
        {
            var column = new DataGridTextColumn()
            {
                Header = tbl.GetColumnName(i),
                Binding = new Binding(string.Format("Cells[{0}]", i))
            };

            dg_Table.Columns.Add(column);
        }
        //end setup data grid columns
    }
}

I think the next step would be to bind the ItemsSource property of the DataGrid to the GetRows method on the MyTable object but I'm not sure how to do that. I thought maybe this could be done using an ObjectDataProvider resource but I can't figure out how to reference a method on the DataContext object.

Can someone help me with the XAML and code behind for this scenario?

+2  A: 

AFAIK you can't bind to a method of a specific instance. You can bind to a property, or a method of an instance created in XAML, or a static method, but not a method of a given instance.

See Bind to a method in WPF.

Here's some binding links that helped me.

EDIT: I realized I should probably try to address your current problem too. :P

First off, I don't have much experience with the DataGrid control in WPF. Having said that, doesn't it automatically generate the columns when you bind the ItemsSource?

The way I'd deal with your problem is by creating a wrapper around the MyTable object, and in the wrapper implementing a property that calls the GetRows method. Set the DataContext to the wrapper and bind the ItemsSource to the property.

Cameron MacFarland
It is strange that you can't bind to the return value of a method on an object that was not created via XAML.
spoon16
+1  A: 

It's very easy using a value converter to index the Cells array. The parameter to the converter is the index:

  ...
    var column = new DataGridTextColumn()
    {
      Header = tbl.GetColumnName(i),
      Binding = new Binding
      {
        Converter = CellAccessConverter.Instance,
        Parameter = i
      }
    }
  ...

Here is the converter itself:

  private class CellAccessConverter : IValueConverter
  {
    public static readonly Instance = new CellAccessConverter();
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      return ((MyTableRow)value).Cells[(int)parameter];
    }
    object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
      throw new NotImplementedException();
    }
  }

Enjoy!

Ray Burns