Background
Recently I started working on Silverlight technology. Silverlight has very good support for databinding. The databinding support is extended to WPF and even Windows Phone 7 development. Because of enhanced databinding support it becomes very easy to build applications which have clear separation of concerns. We can use best practices to build applications which follow presentation patterns like MVC, MVP or MVVM. In my previous organization we had used MVP pattern with WPF. In the current one we are trying to implement MVVM with Silverlight. Here is a very simplistic example of using MVVM with Silverlight 4 application.
Get started with Silverlight MVVM application
MVVM is an acronym for Model-View-ViewModel. In simplistic terms Model is usually the data that we want to use. It can be represented in any form like a POCO class, an XML object or an Entity Framework object. It’s a form of data that needs to be handled in the application. The View is the user interface that is used to show the graphical representation of this data. And the ViewModel is the glue which binds the View and the Model.
Lets look at some of the things that are required for a MVVM enabled application. We’ll be using databinding extensively to bind data from the ViewModel to the View which are mostly user controls in Silverlight. In XAML we specify the binding for different types of controls. The binding is not just limited to controls like TextBox and TextBlock but also to Buttons. Any button that inherits from ButtonBase class like Button and HyperLink button in Silverlight support CommandBinding. This means that we can use databinding to bind a command to a button. The command is an implementation of the ICommand interface provided by Silverlight.
Lets get started with a Silverlight 4 application in VS 2010. We’ll create a very minimal UI similar to Google search with just a textbox to enter some text and a button to execute some action. The final UI will look like
We’ll not enable the button until some text is entered in the textbox.
The traditional way of developing this is to have a label to display the message “Enter text for search”, a textbox for entering the text and the button. We would have the property for button IsEnabled set to false by default and on TextChanged event of the textbox, we would have enabled the button. And finally in the Click event handler of the button we would have written the code to perform the search using the search text. This is what Jesse Liberty called the “Coded” way in his wonderful presentation during the Silverlight FireStarter event. If you like watching technical videos (like me ) please do a Google or Bing search for Jesse Liberty and Silverlight Firestarter event to watch this wonderful video filled with fun.
Enter MVVM and we find that many of this are rendered useless. We no longer need to give names to controls and access their properties from the code behind files. We no longer write code in event handlers like Click for buttons. We don’t assign values using properties like txtSearch.Text. We leverage the Silverlight frameworks databinding capabilities to achieve the same results but in a much more elegant way. Lets look at the XAML for the MainWindow user control
<StackPanel x:Name="LayoutRoot">
<TextBlock Text="Enter text for search" Height="30" HorizontalAlignment="Center" Margin="5"/>
<TextBox Height="30" HorizontalContentAlignment="Center" Width="300"/>
<Button
Content="Search"
Height="30"
Width="100"
Margin="10"/>
</StackPanel>
For databinding to work seamlessly, we need a ability to notify the view when the data changes in the Model or the source. The INotifyPropertyChanged interface comes in very handy for this. This interface has only one requirement which is to fire the PropertyChanged event. When the event is fired any UI element that is bound to the property gets notified and the updates are propagated to the view automatically. Usually ViewModel implements the INotifyPropertyChanged interface. The View binds to the properties of ViewModel and when the value of the property changes, the View gets updated.
So in our case lets start with the ViewModel for the MainPage which is called MainPageViewModel. We need a property to store the value of the search text that is entered in the above search textbox. Lets name this property SearchText. We also want to make sure that the Search button is disabled if there is no text entered by the user. So we’ll have another property called HasText. When the text is entered for search we can set the HasText property to True. We’ll bind this property to the Search button using databinding as follows
<Button
IsEnabled="{Binding HasText}"
Content="Search"
Height="30"
Width="100"
Margin="10"/>
How do controls know about properties of the ViewModel
In order for the button or any other control to bind to a property of the ViewModel it needs to be associated with the View. This can be done in different ways. One such way is in the code behind file we can instantiate the ViewModel and set it as the DataContext for the View.
public MainPage()
{
InitializeComponent();
DataContext = new MainPageViewModel();
}
Many people don’t like this approach. They advocate that the code behind for view should not contain a single line of code. For time being we’ll use this approach. Alternately we can also add it as a Resource in the XAML. But lets not get into the details of that. If we run the application now we’ll see that the Search button is disabled. We did not give any name for the button or did not use any Id of the button to set the isEnabled property. Everything was done using databinding.
Lets move a step forward and bind the text in the textbox to the SearchText property of the ViewModel.
<TextBox Text="{Binding Path=SearchText, Mode=TwoWay}" Height="30" HorizontalContentAlignment="Center" Width="300"/>
Once again we take advantage of the databinding to bind to the property SearchText. We also set the mode to TwoWay. Please note the syntax for data binding. Its {Binding <PropertyName>}. Most of the times when we are new we forget to use the correct syntax and only put the property name instead which does not bind the values. So once again without using any Name or Id for the textbox we are able to populate it with the search text. Lets see how we can enable the button when there is a text entered in the textbox. If we were using the “Coded” way we would have reset the HasText property to true on TextChanged event. But since we don’t write code into codebehind class we need to find an alternative.
In MVVM we use Commands to communicate between View and ViewModel. So lets create a command called SearchCommand in our ViewModel and bind it to the button. The SearchCommand is of type DelegateCommand which implements the ICommand interface. DelegateCommand has two functionalities. One is to identify if the command can be executed and the second one is to execute the command. This is done using two constructor arguments one of which is a delegate to the callback function which needs to be executed. And the other one is the predicate which identifies whether the execute function can be executed based on certain condition or not. Here is an implementation of DelegateCommand
public class DelegateCommand : ICommand
{
public event EventHandler CanExecuteChanged;
private Func<object, bool> canExecute;
private Action<object> executeAction;
private bool canExecuteCache;
public DelegateCommand(Action<object> executeAction, Func<object, bool>canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
bool tempCanExecute = canExecute(parameter);
if (canExecuteCache != tempCanExecute)
{
canExecuteCache = tempCanExecute;
OnCanExecuteChanged();
}
return canExecuteCache;
}
public void Execute(object parameter)
{
executeAction(parameter);
}
protected void OnCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
}
So in the ViewModel we instantiate a delegate command as
private ICommand searchCommand;
public MainPageViewModel()
{
SearchCommand = new DelegateCommand(SearchNet, CanSearchNet);
}
public ICommand SearchCommand
{
get { return searchCommand; }
set { searchCommand = value; }
}
private void SearchNet(object obj)
{
MessageBox.Show("Searching for " + SearchText);
}
private bool CanSearchNet(object arg)
{
return hasText;
}
So we have set the predicate as CanSearchNet which decides whether the command can be executed or not. If it can execute, it calls the SearchNet method which just shows the MessageBox with the entered text. Note: I know all those MVVM experts will be saying this is not right because I am calling the MessageBox directly. I’ll show how to remove this dependency on MessageBox in future post. You can refer to my other post on how to use DialogService to remove dependency on MessageBox.
Once this is done, we need to bind this command to the button so that it gets executed when the button is clicked. This is done as follows
<Button
Command="{Binding SearchCommand}"
CommandParameter="{Binding SearchText}"
IsEnabled="{Binding HasText}"
Content="Search"
Height="30"
Width="100"
Margin="10"/>
We set the SearchCommand as the command binding and also the SearchText as the command parameter because we want the execution of the command to depend on the availability of the text.
The last thing we need to do here is to fire the PropertyChanged event so that databinding infrastructure updates the bindings for the controls when the text changes.
public string SearchText
{
get { return searchText; }
set
{
searchText = value;
if (searchText.Length > 0)
HasText = true;
else
HasText = false;
OnPropertyChanged("SearchText");
}
}
We do it in the setter of the SearchText property. Depending on the length of the text we set the HasText property to true or false. And we fire the OnPropertyChanged event for SearchText property. Once we set the HasText property it internally fires the PropertyChanged event as follows
public bool HasText
{
get { return hasText; }
set
{
hasText = value;
OnPropertyChanged("HasText");
}
}
This is what causes the button to be Enabled or Disabled.
Conclusion
The advantage of using a ViewModel is that we can test the functionality without depending on UI. As of now this post is sufficient for demonstrating the basics of MVVM. I'll cover unit testing the ViewModel in future post. So the basic things required for MVVM are a view model which has the ability to fire PropertyChanged event, a view which binds to the properties of ViewModel using databinding. And if we need to perform any action on click of button etc then a command which can be bound to the button.
There is lot of boilerplate code in this example, like the DelegateCommand class. We can eliminate this if we are using any of the open source MVVM frameworks like MVVM Light or Caliburn or Prism 4. Different people have different terminology for the implementation of ICommand. Josh Smith calls it RelayCommand, MVVM LIght refers to it as DelegateCommand etc. But they essentially perform the same task. Hope this example was a good starting point.
As always I have uploaded the complete solution which can be downloaded at http://dl.dropbox.com/u/1569964/Silverlight/SilverlightBasicMVVM.zip
Until next time Happy Programming