I've been writing about ViewModel (aka MVVM) pattern (here, here, here and more) and implementing it in Silverlight.FX for quite some time now, and it continues to be an exciting area for further thinking, and prototyping. This time around I want to cover how ViewModel and MVC fit together in an application at the same time.
I have put together a set of navigation features into Silverlight.FX: a Page base class, a PageFrame control, and a Navigate trigger action. The PageFrame class by default maps URIs to Page types automatically, but at the same time supports plugging in an MVC PageLoader that maps URIs to Controllers and Actions, and maps ActionResults resulting from those actions into visuals or Pages.
Specifically the controller and the action methods enable writing navigation logic that runs in the context of when a view is being loaded as a result of loading a URI. The result of such an action, and navigation, is a Page and its associated view model. The view model on the other hand encapsulates interaction logic, i.e. the commands and operations and associated view state that come into play as the end-user interacts with the UI. Hopefully this post will show both using a sample application.

The diagram depicts the different building blocks and their relationships.
The Frame control hosts the pages and loads URIs when navigation occurs. The URI loading is performed by routing requests to Controller and its Actions. The controller performs any navigation logic, and potentially uses the data model and data access layer to load any relevant data as part of executing the action. The resulting ActionResult is mapped to a Page and its associated View Model. The view model contains properties, methods and events to encapsulate view state and interaction logic. The view consumes its view model by virtue of data-binding and commands, and subscribes to view model notifications using event triggers.
The Sample Application
In order to illustrate the ViewModel pattern working together with navigation and MVC, I've put together a fairly straightforward sample in the form of a News Widget application. This widget allows searching for news articles and listing the latest news articles by using the recently published New York Times Newswire API.
You can run the live sample as well before reading further to get a sense of what the application does, and the navigation functionality at play.
The rest of the blog post builds this application step by step:
- - Implement the Controllers
- - Populate the IoC container to fulfill controller dependencies
- - Implement the corresponding Views
- - Implement the main window containing the PageFrame and the Navigation Buttons and Search UI
Implementing the Controllers
Controllers are classes that derive from the Controller base class, and are located within a Controllers namespace. They contain Actions, which are public methods that return either ActionResult or Task<ActionResult>. The latter is to support async actions, which is key in the realm of Silverlight, since a controller performing network access to load some data is going to need to do async work behind the scenes.
In this application, I am going to have two controllers: HomeController and NewsController.
namespace NewsWidget.Controllers {
public sealed class HomeController : Controller {
public ActionResult About() {
return View("About");
}
}
}
HomeController is quite basic. It doesn't contain much logic, other than producing a ViewActionResult indicating that the view named "About" must be used to render the result of invoking the controller.
public sealed class NewsController : Controller {
private INewsService _newsService;
public Task<ActionResult> List() {
Task<ActionResult> task = new Task<ActionResult>();
_newsService.GetNews(/* limitToLastDay */ true,
OnNewsItemsAvailable, task);
return task;
}
public Task<ActionResult> Search(string query) {
if (String.IsNullOrEmpty(query)) {
throw new ArgumentNullException("query");
}
Task<ActionResult> task = new Task<ActionResult>();
_newsService.Search(query, OnNewsItemsAvailable, task);
return task;
}
private void OnNewsItemsAvailable(IEnumerable<NewsItem> newsItems,
object userState) {
IEnumerable<NewsItem> orderedItems =
newsItems.AsQueryable().
OrderByDescending(i => i.PublishDate);
ViewActionResult result = View("List");
result.ViewData["Items"] = orderedItems.ToArray();
Task<ActionResult> task = (Task<ActionResult>)userState;
task.Complete(result);
}
}
The NewsController is more interesting. It has two actions: List and Search. The Search action takes a string parameter. Rather than returning ActionResult, both of these return Task<ActionResult> as they both perform some async work to load news articles. When the async work is completed, they produce a ViewActionResult indicating a view named "List" should be used. The ViewData is populated with the list of news items that were just retrieved.
The controller has basically encapsulated the navigation logic - how latest news articles are retrieved, and how they are searched. Loading of news articles happens as a result of navigation, before a page is loaded into the visual tree. Consequently, the new page is not empty when it first shows up on screen, which makes it possible to transition to it with a visual effect such as cross-fade. It also allows the controller to fail the navigation if there is an error loading the data, or perform a redirect, should something like a login be required. Effectively, introducing the controller pattern allows implementing the logic that is closely associated with navigation in the application separated from the UI itself, rather than putting it into the view model that only gets a chance to do something after navigation to the Page has completed.
You'll notice the use of an INewsService. That is a dependency of the NewsController. At runtime, the NewsController works against an implementation of INewsService that issues web requests to the New York Times Newswire API. This has been factored out and abstracted via an INewsService, so it can be mocked at unit test time, if you'd like to test this Controller in isolation. As such, at runtime I'd like to use IoC to fulfill the dependency (I first described this here). So I'll add the following constructor:
public sealed class NewsController : Controller {
private INewsService _newsService;
public NewsController([Dependency] INewsService newsService) {
_newsService = newsService;
}
}
I have the following implementation of INewsSerivce:
namespace NewsWidget.Services {
[Service(typeof(INewsService))]
public class TimesNewswireService : INewsService {
...
}
}
In my Application, in NewsApplication.xaml, I'll declare the actual implementation of this service, which is used to populate the default container against which dependencies are resolved.
<fxapp:XApplication
xmlns:fxnav="clr-namespace:SilverlightFX.Applications;assembly=SilverlightFX"
xmlns:appsvc="clr-namespace:NewsWidget.Services">
<fxapp:XApplication.Components>
<appsvc:TimesNewswireService />
</fxapp:XApplication.Components>
</fxapp:XApplication>
Creating the Views
So now that I have my controllers, its time to implement the views. Views are basically pages, along with a view model if they need one. Again, AboutPage is really simple. It is a page with some static text content:
<fxnav:Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
x:Class="NewsWidget.Views.Home.AboutPage">
<TextBlock Text="..." />
...
</fxnav:Page>
ListPage is much more interesting. The ListPage displays a list of news articles. It also provides the end user with the ability to filter the list down to those news articles published today. In other words it has some interaction logic. This will be facilitated with a view model. Here is the XAML:
<fxnav:Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fxui="clr-namespace:SilverlightFX.UserInterface;assembly=SilverlightFX"
xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
x:Class="NewsWidget.Views.News.ListPage"
ModelType="NewsWidget.Views.News.ListPageModel">
<fxui:XGrid Rows="*,Auto">
<fxui:ListView Style="{StaticResource newsItemListStyle}"
DataSource="{Binding ListItems}">
<fxui:ListView.ItemTemplate>
<DataTemplate>
...
<TextBlock Text="{Binding Headline}" TextWrapping="Wrap" />
<TextBlock Text="{Binding Section}" />
<TextBlock Text="{Binding Summary}" TextWrapping="Wrap" />
...
</DataTemplate>
</fxui:ListView.ItemTemplate>
</fxui:ListView>
<CheckBox x:Name="filterCheckBox" Grid.Row="1" HorizontalAlignment="Center"
IsChecked="{Binding FilterToday, Mode=TwoWay}"
Content="Show only today's news" />
</fxui:XGrid>
</fxnav:Page>
And here is the corresponding view model, ListPageModel, which is associated with the Page via the ModelType property.
public class ListPageModel : Model {
private bool _filterToday;
public bool FilterToday {
get { return _filterToday; }
set {
_filterToday = value;
RaisePropertyChanged("FilterToday", "ListItems");
}
}
public IEnumerable<NewsItem> Items { get; set; }
public IEnumerable<NewsItem> ListItems {
get {
if (_filterToday == false) {
return Items;
}
return Items.Where(item => item.PublishDate.Date == DateTime.UtcNow.Date);
}
}
}
The ViewModel exposes the Items property. This is initialized using the ViewData generated by the controller action (the ViewData dictionary contains an item named "Items" as added by the controller action). It also exposes a ListItems property which is either all the items, or a list of items filtered to the current date. The ListView in the UI is bound to the ListItems property. The filterCheckBox in the UI is two-way bound to the FilterToday property on the ViewModel. This allows toggling the set of items shown in the UI. Together these properties and filtering behavior represent the interaction and interaction logic of the view.
Performing the Navigation
Now that we have our controllers and the views, we need to actually perform navigation and display the pages in the UI of the application. I'll first add a PageFrame, the control that does this, in the main window of the application.
<fxui:Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fxui="clr-namespace:SilverlightFX.UserInterface;assembly=SilverlightFX"
xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
x:Class="NewsWidget.NewsWindow">
<fxnav:PageFrame x:Name="mainFrame">
<fxnav:PageFrame.Loader>
<fxnav:MvcPageLoader />
</fxnav:PageFrame.Loader>
<fxnav:PageFrame.Transition>
<fxtransition:CrossFade Duration="00:00:0.25" />
</fxnav:PageFrame.Transition>
</fxnav:PageFrame>
</fxui:Window>
On the PageFrame, I've replaced the default Loader (which maps URIs to Pages directly) to instead use an MvcPageLoader. The MvcPageLoader understands the MVC pattern. Specifically it does two things. First it performs routing. It resolves a URI into a Controller type and an associated action (along with action parameters), and then invokes the action. Secondly, it processes the resulting ActionResult from the control to perform the work of a view engine to produce a Page visual.
The MvcPageLoader in Silverlight.FX contains a few conventions. URIs are of the form:
/ControllerName/ActionName/[PathContainingPositionalParameters]?[QueryStringWithNamedParameters]
Optionally if there is only one Controller in the application, the ControllerType can be specified on the MvcPageLoader and that simplifies the URI to:
/ActionName/[PathContainingPositionalParameters]?[QueryStringWithNamedParameters]
Controllers are looked up in a Controllers namespace by appending the "Controller" suffix to the name. Views are located within a subnamespace named after the Controller name within a Views namespace of the application. For example, the "About" view referred by the HomeController is a page, AboutPage, defined in the Home subfolder within the Views folder. Similarly the "List" view referred by the NewsController is a page, ListPage, defined in the News subfolder within the Views folder. This can be seen in the project structure as shown in the Solution Explorer screenshot above.
Today the only view engine logic has the MvcPageLoader looking up Pages corresponding to a ViewActionResult. In the future I'll be extending it to look for DataTemplates for an ObjectActionResult.
As an aside, PageFrame also supports page-to-page transitions, and I've specified that I want to use a cross-fade effect for this particular application.
Now I need the links themselves. Here are couple of buttons in the main window of the application:
<Button Content="Latest News" Style="{StaticResource linkButton}">
<fxui:Interaction.Triggers>
<fxui:EventTrigger EventName="Click">
<fxaction:Navigate Target="mainFrame"
NavigateUrl="/News/List" />
</fxui:EventTrigger>
</fxui:Interaction.Triggers>
</Button>
<Button Content="About" Style="{StaticResource linkButton}">
<fxui:Interaction.Triggers>
<fxui:EventTrigger EventName="Click">
<fxaction:Navigate Target="mainFrame"
NavigateUrl="/Home/About" />
</fxui:EventTrigger>
</fxui:Interaction.Triggers>
</Button>
As you can see I've used a Navigate trigger action to cause navigation to occur when a Button is clicked. The Navigate trigger action can be associated with any event of any control... so I could also have had an image as my navigation UI and perform navigation in response to the MouseLeftButtonDown event.
The Search functionality is a bit more interesting. Here the view model associated with the main window itself plays a role. Here is the XAML for the search UI:
<fxnav:Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:fxui="clr-namespace:SilverlightFX.UserInterface;assembly=SilverlightFX"
xmlns:fxnav="clr-namespace:SilverlightFX.UserInterface.Navigation;assembly=SilverlightFX"
x:Class="NewsWidget.Views.News.ListPage"
ModelType="NewsWidget.Views.News.ListPageModel">
<TextBox x:Name="searchTextBox" Width="140" Text="{Binding SearchText, Mode=TwoWay}">
<fxui:Interaction.Behaviors>
<fxui:AutoCommit ButtonName="searchButton" />
</fxui:Interaction.Behaviors>
</TextBox>
<Button x:Name="searchButton" Content="Search" Style="{StaticResource linkButton}">
<fxui:Interaction.Triggers>
<fxui:EventTrigger EventName="Click">
<fxaction:Navigate Target="mainFrame"
NavigateUrl="{Binding SearchUrl}" />
</fxui:EventTrigger>
</fxui:Interaction.Triggers>
</Button>
</fxnav:Page>
Here is the associated view model:
public sealed class NewsWindowModel : Model {
private string _searchText;
public string SearchText {
get { return _searchText; }
set {
_searchText = value;
RaisePropertyChanged("SearchText", "SearchUrl");
}
}
public string SearchUrl {
get {
if (String.IsNullOrEmpty(_searchText)) {
return null;
}
return "/News/Search?query=" + _searchText;
}
}
}
In the UI, the Search TextBox is two-way bound to the SearchText property. Whenever the SearchText property is changed, the SearchUrl, a computed property is also changed. The Navigate trigger action in the UI has its NavigateUrl property bound to SearchUrl. So when the user clicks the Search button in the UI, the computed SearchUrl is used to perform the navigation.
So again what you see is the view model facilitating interaction logic. Specifically it encapsulates the logic of building a URL to the Search action on the controller in response to the user entering in some keywords to search for in the SearchTextBox.
Summary
This application shows how both MVC and ViewModel (aka MVVM) co-exist in a single application.
The MVC pattern enables writing navigation-oriented logic in the form of a set of synchronous or asynchronous action methods that produce corresponding ActionResults. The ViewModel pattern allows writing interaction logic in the form of properties representing view state, methods representing operations and events (not shown here) representing notifications.
Both patterns are common from the perspective that they allow separating logic out from the UI, so they can be written and tested in isolation. Both can contain dependencies that need to be fulfilled via an IoC container and dependency injection.
The sample is part of Silverlight.FX. You can download the framework sources, the sample sources (along with several other samples), and the framework binaries. You can follow further development on the project page or at its associated GitHub repository. Aside: While all this should work in Silverlight 3 as well, I have started porting Silverlight.FX to Silverlight 3 to make use of some new capabilities, and hope to have that version ready soon.
Hope you found this interesting even though its a bit on the long side. I'd love to hear your thoughts and suggesstions on the pattern, as well as the implementation in Silverlight.FX.