Dynamically specify and change a Silverlight DataGrid's columns during runtime (MVVM) - silverlight

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).

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

Related

WPF MVVM - Binding DataGrid to ObservableCollection of Model

I am pretty new to WPF MVVM, so pardon me if I understood MVVM concepts wrongly.
I have a DataGrid in my View, which I have bound the ItemsSource to an ObservableCollection<M> in the ViewModel. The M class is a Model class. However, the M class has bool properties, which are to be displayed in the DataGrid as "Yes/No" strings.
Currently, I am using a Converter to convert the bool value to string. But, it just feels wrong for the ViewModel to expose a list (ObservableCollection) of a Model to the View. I have also read that in MVVM, conversions should be done at ViewModel. So, what is the right way to implement this the MVVM way for a DataGrid?
In an ideal world, you would wrap your Model objects in their own ViewModel so that your ObservableCollection contains a ViewModel type with those bool Model properties converted to Yes/No string properties.
However, in a pragmatic world, if you are not editing those values, I wouldn't bother except to note that if you are exposing many of those bool properties and have many thousands of rows, you will take a performance hit on rendering the grid while the DataGrid instantiates a Converter per property and row.
Using converters is not a wrong way. As per my suggestion, you should bind the data as you're doing now and in the view you can create and use a BoolToStringConverter for converting the boolean value to yes or no.

How to manipulate WPF window controls (tabs, textboxes, listboxes) from a ViewModel

I'm kinda new to WPF. I'm making an app using WPF (all the UI controls are already fixed) and MVVM but most of the events are in the code-behind. I'm in the process of clearing the code-behind but I have codes like (the ones below) to switch through tabs, and to trigger visibility of controls depending on parameters:
tabItem1.Selected = true;
textBox1.Visibility = Visibility.Hidden;
lbxHusbandsWives.Items.Add(txtHusbandsWives.Text + '/' +
cbxHusbandsWivesCountry.Text + '/' +
dpHusbandsWives.SelectedDate.Value.ToShortDateString());
How can I do that in the viewmodel? Well, inside a Command? So I can clear the messy code-behind? Thanks for your help. :)
As I said many times before, MVVM doesn't mean "no code behind". There are things that you can or should do in code-behind, as long as they are strictly related to the view and are not necessary for the ViewModel to work properly.
That being said, in most cases you don't need to do anything in code-behind. You normally use bindings to control the view from the ViewModel. This allows the ViewModel to be completely ignorant of the view: it just exposes properties that the view can access, and sends notifications when the values of the properties change. The ViewModel should definitely not manipulate the view or its components.
Everything in the code you posted can be done with bindings in XAML:
textBox1.Visibility can be bound to a bool property of the ViewModel, using a BooleanToVisibilityConverter
lbxHusbandsWives.ItemsSource can be bound to an ObservableCollection in the ViewModel (an ObservableCollection notifies the view when items are added to or removed from it)
txtHusbandsWives.Text, cbxHusbandsWivesCountry.Text and dpHusbandsWives.SelectedDate can also be bound to properties of the appropriate type

MVVM and Custom Controls?

I'm working on PRISM application with modules, MVVM and so on. I understand PRISM pretty good now and I understand value of MVVM. All those things good to deliver business value which comes from testability, "uniformity" and so on.
But now I'm stuck with certain interaction issues. I already spent hours and hours trying to see how I set focus in Silverlight via MVVM. All this additional behaviors, attached properties, triggers. It just seems like bunch of junk code with MVVM being root cause.
For example, I need to create Lookup control which is basically textbox with button and popup window. This control itself needs lot of focus control, it needs to overlay view over parent (popups) and so on. It seems to be pretty easy to create it with code-behind, stick it into separate library and move on. My business forms will use this control inside my nice MVVM PRISM.
So, question is.. Is it justified to use code-behind in isolated islands like controls and keep MVVM and TDD for actual code that brings business value?
Is there line where you say "MVVM is not going to be used here" ?
I see absolutely nothing wrong with using Code Behind providing that the code is related to view-specific properties, such as setting Focus. Your ViewModel should never need to know about or care who or what has focus, since that is a View-Specific concept.
Usually I build UserControls in two ways: they are either built for a specific Model or ViewModel, or they are meant to be generic and have their values provided by whoever calls them.
In the case of the former, such as if I wanted a SearchResultsPopup, I would build the UserControl expecting to have something like a SearchResultsViewModel as the DataContext.
For example, my UserControl would expect to find the following properties on it's DataContext, and would use them in bindings to build the View.
ObservableCollection<SearchResult> Results
SearchResult SelectedResult
bool IsOpen
ICommand OkCommand
ICommand CancelCommand
I could then use the UserControl like this:
<local:SearchResultsPopup DataContext="{Binding MySearchResultsVM}" />
In the later situation, where I am creating something generic which can be used by any Model or ViewModel, I would use custom Dependency Properties to provide my UserControl with the values it needs to bind to.
So in this example, I would have DependencyProperties for
bool IsOpen
ICommand OkCommand
ICommand CancelCommand
And my XAML would look something like this:
<local:GenericPopup local:GenericPopup.IsOpen="{Binding IsPopupOpen}"
local:GenericPopup.SaveCommand="{Binding SavePopupCommand}"
local:GenericPopup.CancelCommand="{Binding HidePopupCommand}">
<local:MySearchResultsView ... />
</local:GenericPopup>
In summary, your UserControl is either a reflection of your ViewModel (meaning it becomes a View), or it is provided values by the View. The ViewModel doesn't care either way.

Can MVVM Usercontrols have property defined in codebehind?

I have a WPF user control ...which is in MVVM. The user control(which contains a listview) need data from the page (where it is included). I have to set a property to get this data input. Will this comply with MVVM...if not, what is the way for the same?
I'm afraid this won't be correct in MVVM design pattern. try to stick to your view model to define properties. Why don't you consider moving that property to control's vm?
Use an ObservableCollection rather.
ObservableCollection<myModel> myOC = new ObservableCollection<myModel>();
where myModel is a class that has to be constructed transforming your columns in the DataTable to Properties.
In your MainViewModel, loop through the DataReader and create myOC out of it.
Now bind myOC to a ListView in your page.
The DataTemplate of ListView should be a view(UserControl) drawing data from a ViewModel constructed out of myModel
But your UserControl has the entire ListView inside. If that is on purpose, then let me know the entire design to give a better idea.

Can MethodParameters in an ObjectDataProvider be databound to other controls?

I've been exploring WPF and XAML for a while now, but have hit a slight stumbling block revolving around binding to a method.
My situation is:
There is a ComboBox bound to a DataTable. There is a ListBox bound to the return value of a method (GetDates) via an ObjectDataProvider. One of the input parameters of the method GetDates is an Id stored in the ComboBox/DataTable.
How can I bind a MethodParameter in the ObjectDataProvider to a particular value of the SelectedItem of a ComboBox (in this case, the SelectedItem is of type DataRowView)? Alternatively, am I missing a better way of solving this problem?
I can see ways out of it by using the code-behind, but I'd like to know if there's a more XAML-y solution. It's always useful to pick up little tips and tricks, even if it turns out not to be the best fix to this problem.
http://msdn.microsoft.com/en-us/library/system.windows.data.objectdataprovider.methodparameters.aspx
This seems to describe what I need - although it's actually trying to answer a different problem.
(Aside: Is it just me or is that example on MSDN trying to do too much all at once?)
By binding the ItemsSource of the ComboBox to a DataTable, and the SelectedItem of the ComboBox to a MethodParameter (with a converter to extract the value I need from the DataRowView), the ObjectDataProvider will have the parameter it needs.
It would probably be easier to read/follow/maintain if I just hooked into the ComboBox.SelectionChanged event.

Resources