DataGrid with variable number of columns?

Asked By Ahmad
11-Aug-10 07:19 PM
Earn up to 0 extra points for answering this tough question.
Basically, if you use MVVM you bind your datagrid to a collection of objects, each row represents an object and each column represents a property in that object.
But if you want it such that the number of columns is variable, and editable, that is impossible because the number of properties (which columns represent) in any class is fixed.
I wish I can bind the datagrid to a 2 dimentsional array or a collection of collections of values, such that:

adding a collection to the outer collection will add a row to the grid 
and adding a value to an inner collection will add another column to the grid.

(Imagine a senario where every column represents a date and every row represents a currency and every cell represents the exchange rate of that currency in that date, and you want to dynamically change the number of columns (dates) and their range using MVVM pattern...

Please Help

  re: DataGrid with variable number of columns?

Christopher replied to Ahmad
17-Aug-10 01:18 PM
Hi Ahmad

I have exactly the same problem in that the app has no Idea of how many columns  or rows I have until after user data is loaded so they ave to be loaded dynamically.

Did you perhaps find a solution to your problem?

Chris

  re: DataGrid with variable number of columns?

Ahmad replied to Christopher
17-Aug-10 05:06 PM
Hello Chris,

I have found a solution, though probably not very elegant.
First I define a new useful class called ObservableDictionary like so (I put it in the utilities folder in my project)


class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged
{
  // Implementation
}


This observable dictionary is just like normal dictionary except it implements INotifyCollectionChanged and so is suitable for binding.
Second I store the data in my view-model as a 2 dimension ObservableDictionary like this:

public ObservableDictionary<string, ObservableDictionary<string,double> Data { set; get; }


You access your data like this: Data[rowHeader][columnHeader].
Third I define an extension method in my View source file called GenerateColumns like so:


public static void GenerateColumns(this DataGrid datagrid,
  ObservableDictionary<string, ObservableDictionary<string, double> data)
{
  datagrid.Columns.Clear();
  if (data.Count == 0) return;
  datagrid.ItemsSource = data;
 
  foreach (string columnHeader in data.First().Value.Keys)
  {
    DataGridTextColumn column = new DataGridTextColumn
    {
    Header = columnHeader,
    Binding = new Binding(String.Format("Value[{0}]", columnHeader))
    Width = 80
  };
     datagrid.Columns.Insert(0, column);
  }
}


You pass a reference of your data to that method like this:

MyDataGrid.GenerateColumns( ((ViewModelClass)DataContext).Data );

and your columns will be generated and bound to the Data in the view-model.
For this to work, you need to take care of few things:
1 - In your view-model (where Data is) you should handle CollectionChangedEvent by raising onPropertyChanged("Data") in your view-model class.
2 - you should handle PropertyChanged raised earlier in your view by calling 
GenerateColumns(((ViewModelClass)DataContext).Data)
3 - Make sure not call these if your View's DataContext == null, you can do this by adding this method to your view class

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
  base.OnPropertyChanged(e);
  if (e.Property.Name == "DataContext")
  {
    ((ViewModelClass)DataContext).PropertyChanged += HandlerThatCallsGenerateColumns;
  }
}
 
void HandlerThatCallsGenerateColumns(object sender, PropertyChangedEventArgs e)
{
  if (e.PropertyName == "Data")
  {
    MyDataGrid.GenerateColumns(((ViewModelClass)DataContext).Data);
  }
}


Tell me how it goes...

Regards,
Ahmad

  re: DataGrid with variable number of columns?

Christophe Scherly replied to Ahmad
18-Feb-11 10:55 AM
Hello Ahmad,

I'm very interesting to implement your solution but until now I was unsuccessful.
Do you have a complete solution using your technique?

Create New Account