This post is part of a series of blog posts and videos about the Task-It (task management) application that I have been building with Silverlight 4 and Telerik's RadControls for Silverlight 4. For a full index of a posts, please go here. One of the posts listed in the index provides a full source download for the application.
As I'm gearing up to write a post about dynamic XAP loading with MEF, I'd like to first talk a bit about MVVM, the Model-View-ViewModel pattern, as I will be leveraging this pattern in my future posts.
Your first question may be, "why do I need this pattern? I've been using a code-behind approach for years and it works fine." Well, you really don't have to make the switch to MVVM, but let me first explain some of the benefits I see for doing so.
No event handlers?
Another nice thing about MVVM is that you can bind your UserControls to the view model, which may eliminate the need for event handlers in your code-behind. So instead of having a Click handler on a Button (or RadMenuItem), for example, you can now bind your control's Command property to a DelegateCommand in your view model (I'll talk more about Commands in an upcoming post).
Instead of having a SelectionChanged event handler on your RadGridView you can now bind its SelectedItem property to a property in your view model, and each time the user clicks a row, the view model property's setter will be called. Now through the magic of binding we can eliminate the need for traditional code-behind based event handlers on our user interface controls, and the best thing is that the view model knows about everything that's going on...which means we can test things without a user interface.
The brains of the operation
So what we're seeing here is that the view is now just a dumb layer that binds to the view model, and that the view model is in control of just about everything, like what happens when a RadGridView row is selected, or when a RadComboBoxItem is selected, or when a RadMenuItem is clicked. It is also responsible for loading data when the page is hit, as well as kicking off data inserts, updates and deletions. Once again, all of this stuff can be tested without the need for a user interface. If the test works, then it'll work regardless of whether the user is hitting the browser-based version of your app, or the Windows Phone 7 version. Nice!
At the top of this post is a link to a sample project that demonstrates a sample application with a Tasks page that uses the MVVM pattern. This is a simplified version of how I have implemented the Tasks page in the Task-It application.When you open the solution in VisualStudio 2010 RC be sure to set MVVMProject.Web as the StartUp Project and MVVMProjectTestPage.aspx as the Start Page.
You’ll notice that Tasks.xaml has very little code to it. Just a TextBlock that displays the page title and a ContentControl.
In List.xaml we have a RadGridView. Notice that the ItemsSource is bound to a property in the view model class call Tasks, SelectedItem is bound to a property in the view model called SelectedItem, and IsBusy is bound to a property in the view model called IsLoading.
In Details.xaml we have a Save button that is bound to a property called SaveCommand in our view model. We also have a simple form (I’m using a couple of controls here from Silverlight.FX for the form layout, FormPanel and Label simply because they make for a clean XAML layout). Notice that the FormPanel is also bound to the SelectedItem in the view model (the same one that the RadGridView is). The two form controls, the TextBox and RadDatePicker) are bound to the SelectedItem's Name and DueDate properties. These are properties of the Task object that WCF RIA Services creates.
In the code-behind of the Tasks control, Tasks.xaml.cs, I created an instance of the view model class (TasksViewModel) in the constructor and set it as the DataContext for the control. The Tasks page will load one of two child UserControls depending on whether you are viewing the list of tasks (List.xaml) or the form for editing a task (Details.xaml).
When the page first loads, the List is loaded into the ContentControl.
In the code-behind we also listen for a couple of the view model’s events. The ItemSelected event will be fired when the user clicks on a record in the RadGridView in the List control. The SaveCompleted event will be fired when the user clicks Save in the Details control (the form). Here the view model is in control, and is letting the view know when something needs to change.
The event handlers toggle the view between the RadGridView (List) and the form (Details).
In TasksViewModel, we instantiate a DataContext object and a SaveCommand in the constructor. DataContext is a WCF RIA Services object that we’ll use to retrieve the list of Tasks and to save any changes to a task. I’ll talk more about this and Commands in future post, but for now think of the SaveCommand as an event handler that is called when the Save button in the form is clicked.
When the TasksViewModel constructor is called we also make a call to LoadTasks. This sets IsLoading to true (which causes the RadGridView’s busy indicator to appear) and retrieves the records via WCF RIA Services.
When the data is returned, OnTasksLoaded is called. This sets IsLoading to false (which hides the RadGridView’s busy indicator), and fires property changed notifications to the UI to let it know that the IsLoading and Tasks properties have changed. This property changed notification basically tells the UI to rebind.
Next let’s look at the view model’s SelectedItem property. This is the one that’s bound to both the RadGridView and the form. When the user clicks a record in the RadGridView its setter gets called (set a breakpoint and see what I mean). The other code in the setter lets the UI know that the SelectedItem has changed (so the form displays the correct data), and fires the event that notifies the UI that a selection has occurred (which tells the UI to switch from List to Details).
One last thing, saving the data. When the Save button in the form is clicked it fires the SaveCommand, which calls the OnSave method in the view model (once again, set a breakpoint to see it in action).
In OnSave, we tell WCF RIA Services to submit any changes, which there will be if you changed either the Name or the Due Date in the form. When the save is completed, it calls OnSaveCompleted. This method fires a notification back to the UI that the save is completed, which causes the RadGridView (List) to show again.
Subscribe to be the first to get our expert-written articles and tutorials for developers!