Introduction
This tutorial will try and explain the advantages and the 'how to' of using MVVMLight within your XAML application so that you can produce code that is maintainable and more importantly testable.
Why Use the MVVM Pattern
The tight coupling of GUI to code-behind has, over the years, meant that testing the code-behind can be some what tricky. In that, how do you mimic the selected event in the GUI to call the bound event code - you can mimic the call to your event code, but how do you get the selected item from the combo (in the GUI) that doesn't exist, as you are not running the GUI but testing the methods that the GUI uses? What was needed was a loose coupling between the GUI and the code-behind, this is where Context classes come in - XAML (Silverlight or WPF) have a concept where a Silverlight page can have a (context) class associated with it for its events and also (more importantly) have setters and getters associated with the bindings to GUI controls. So when a property is updated by its setter, a call to your 'NotifyPropertyChanged
' method in the class 'INotifyPropertyChanged
' will trigger the rebinding to the control.
Install and Integrate MVVMLight Into Your Project
You can download and follow the instructions from Gala's web site here: http://www.galasoft.ch/mvvm/getstarted/.
Or:
Below is how to convert your project to an MVVMLight project after installing NUGet and running the MVVMLight installer:
Binding Scenarios
Commands
A command is basically a reference point for when an event happens in the GUI. The respective command (set in the XAML) will be triggered. In any MVVM design pattern, there is a RelyCommand that will determine if the command's associated method can be executed. Below, you can see that the button's command property has been bound to the 'ButtonCommand
' command in code, in the context class - thus wiring up a (button click) event to this command in code - which in turn will call a method to act upon the command.
Passing a Parameter to a Command
It is possible using a reference to the System.Windows.Interactivity
class to pass parameters to the called command (again, there is a RelyCommand for this type of passing). Below the trigger is the 'SelectionChanged
' event of the textbox, which will call the 'LstBoxChangedCommand
' command with the parameter of the contents of the textbox.
RelyCommand (including passing back parameter)
The RelyCommand will determine if the associated method of the command can be executed. There are a couple overrides for the RelyCommand, in that you can call the RelyCommand with a parameter, or not. Basically, there are two methods that can be called for each version (parameter or not). The only difference (other that expecting a parameter) is that you can fire a 'canExecute
' method to determine if the command is valid to proceed processing. There is also a RelyCommand method that does not take a 'canExecute
' and it will always fire the associated method of the command. For example, you might want the SelectedItemChanged
event of a ComboBox
to always fire, as you do not depend on any other controls\scenarios on the page. In the two images below, you can see the object browser view on the MVVMLight RelayCommand methods - the first one does not take parameters, but the second image shows the signature of the Relaycommand that does take a parameter.
Binding Setter Properties in XAML
Associate a binding with a setter property in the context class (that will be two way so that the changes can be posted back to the control - one way only means that the control tells the property that it has changed). In the image below, you can see that the SelectedItem
is bound to the property 'SelectedTemplate
' - which is a reference to a class in an ObservableCollection
.
MVVM NotifyPropertyChanged Method
With the above binding, and in two way mode, I can make a change to the property (maybe in the method associated with a command); for example, I have selected an item from a combobox - this triggers a command, the method associated with that command then sets a property that is bound to a label - that label with the use of the 'NotifyPropertyChanged
' method will post the update back to the label.
Binding Event Properties in XAML
A developer will want to bind many GUI control events back to commands in the context class. This is possible using the 'System.Windows.Interactivity
' class. We can bind any event in the comboxbox (for example) back to a command in the context class - to get say the selected item in the combobox, we would generally pass a parameter to the command. There is a caveat here, in that the SelectionChanged
event is triggered before the SelectedItem
binding can take place - so in this case, we would pass the SelectedItem
to the command. Knowing that this scenario can happen, but also knowing that we can get around, this can only extend the use of the MVVM design pattern. Basically, an event cannot be triggered to a command in another class and actioned upon. Looking at this image again, you can see that I am binding to an event in the textbox - SelectionChanged
. You can now bind to any event that a control has.
Raising a Separate Command to Execute (Within Another Command Method)
The situation will arise that you need another event\command to fire after you have changed a property or to a separate event - this is possible by using the RaiseCanExecuteChanged
method on the respective command that you wish to evaluate.
Sample Application
This application will need the MvvmLight DLLs added (as they made the size of the project after zipping over 11 MB). If you following the instructions in the introduction using NUGet, uou can add the DLLs easily.
The sample code basically validates what the user types in (the textbox) against the combobox to enable or disable the button (a valid entry is something that is not already in the combobox).
Unit Testing MVVM Code
In the downloadable project above, I created some tests that can be applied to the MVVM context class. Thus, I can mimic the 'KeyDown
' event that will happen in the XAML in my test fixture.