views:

650

answers:

1

What's the best method of dynamically specifying DataGrid columns in the Silverlight DataGrid control at runtime following the MVVM pattern?

What I'd like to do would be bind the "DataGrid.Columns" property to a property in my ViewModel so that, if the user adds/removes columns, I simply update the ViewModel property and the DataGrid would change. Problem is, the "DataGrid.Columns" property can't be bound to (I don't think).

Because this property isn't available nor is the DataGrid control itself available at the ViewModel level, my current approach is to step outside of the MVVM pattern for this particular implementation and capture certain events in View's code-behind using MVVM Light's Messenger class and then talk directly with the DataGrid control to achieve this capability. I know this is a general statement to this approach without details but is there an easier way... or maybe not so much easier, but a better way that adheres to the MVVM pattern a little better?

It's driving me crazy that the DataGrid control's Columns property can't be bound... seems like such a simple thing.

FYI - Before it's suggested to use AutoGenerateColumns = True, the class being bound for each item in the collection that's bound to DataGrid.ItemsSource does not have individual properties to identify what is bound to the columns... it's a collection property that contains the columns in order to keep them completely dynamic so that particular path is out. Also, handling the AutoGeneratingColumns and using e.Cancel to show/hide columns is also iffy for this same reason (I think).

A: 

Hi,

I agree that it is a pain that DataGrid.Columns cannot be bound to. My recommendation here would be to define your columns in the ViewModel in an ObservableCollection. In the View (code behind), handle the CollectionChanged event of this ObservableCollection, and modify the DataGrid.Columns in code.

While this solution is less elegant, it is straightforward. For your ViewModel, you can unit test that the CollectionChanged event is raised properly when columns are added, removed or moved. The View code cannot be tested, so I guess this is something you need to live with. The advantage is that, if some day the DataGrid.Columns property can be databound, it will be easy to refactor this to remove the code behind.

Another way (I think) would be to create an attached behavior or a Blend behavior to take care of this. Attach it to the DataGrid; instead of binding to the DataGrid.Columns directly, bind to a property on the behavior, and have the behavior modify the DataGrid (the AssociatedObect) directly.

Does that make sense? Cheers, Laurent

LBugnion
After deciding to implement your first suggestion which I agree is "less elegant" but gets the job done, I stumbled across an alternate method that I'm testing out.The class detailed here: http://goo.gl/DsO3 by Mr. Bodurov using IL to dynamically create a class with properties which allows me to use DataGrid.AutoGenerateColumns = true and just bind right to the collection with the DataGrid columns showing up automatically...so we can potentially bind right to it in the VM. It's promising but there are a few gotcha I'm trying to work out regarding binding like value propagation to the model.
Biggert
Sounds interesting, please blog about it when you are done, I would be interested to hear about your experience.
LBugnion