Browse by Tags

All Tags » mvvm   (RSS)

I have to admit that I may have rolled my eyes a bit when I first learned about the KnockoutJS library. It sounded too much like forcing a square peg into a round hole. Isn’t Model-View-Controller (MVC) already it’s own pattern? Does it make sense to apply something like Model-View-ViewModel (MVVM) to HTML? I already had enough issues dealing with MVVM on the platform it was designed for, XAML and C# (WPF and Silverlight). Some people simply didn’t get the pattern, others were pushing it without really understanding its benefits, and many applications completely and unnecessarily overcomplicated their implementation of the pattern. So before we talk about whether it makes sense in HTML-based applications, we first need to agree on what the benefits of the pattern are.

I’ve heard many opinions regarding this and have not only read lists, but also published my own. You might hear things like “decoupled code” or “best practices” or “modularity.” Many of the benefits often cited are really just good coding practices that should be implemented regardless of the user interface (UI) pattern being followed. After looking at all of the different benefits, coding using different patterns, and spending several years building enterprise Line of Business (LOB) Silverlight applications it really boils down to two specific benefits:

  1. Testability – MVVM improves the testability of your application. This is only a benefit if you feel that testing itself provides benefits.
  2. Designer-Developer Workflow – MVVM facilitates a separation of UI and presentation logic concerns from the business layer that makes it easy to streamline the development process by allowing design cycles to happen in parallel with development. A great example of this was the Microsoft Looking Glass project that had more than 6 designers working on design for over 3 months while we developed it. The total delivery time was around 4 months, instead of the typical 7 (3 + 3 + 1 month of testing) you get when the design process has to happen sequentially and not parallel to the development effort.

The design-time views even without the workflow are useful but not critical in my opinion. So how does this all translate to HTML-based development?

HTML is Not XAML

The first distinction that Silverlight and WPF developers need to make is between HTML and XAML. They are often compared, but are they really similar?

XAML is a declarative language for instantiating an object graph. While it is commonly used for UI elements, it can create special objects like styles that apply theming to elements, behaviors, triggers, even code that has no visual artifacts whatsoever. XAML by nature is extensible. You can create new elements that map to custom classes, and extend the attributes of existing elements through attachments and custom markup extensions. This strict relationship between the declaration and the object graph means that invalid XAML is a Bad Thing™ and causes the XAML parser to choke. If it cannot instantiate an object or set a property, the entire visual tree is invalid and that’s that.

HTML is declarative markup. It defines a structure. Most of that structure is simply containers for information. There is minimal behavior. Elements are pre-defined based on an accepted standard and arbitrary extension or customization is not supported. The containers provide some structure to information, but it is ultimately CSS that defines the UI and to an extent some of the presentation logic and behaviors. JavaScript handles the object graph for the page, but neither CSS nor HTML declaratively instantiate JavaScript objects. It’s the other way around – JavaScript in the context of a page is more like parsing an XML Document in C# code than it is like having XAML and code-behind. The closest thing to XAML in the web world is server-side code that through whatever mechanism emits the HTML and JavaScript code elements of a web page.

Because HTML is just structure, browsers can also be very forgiving in their parsing. They do not have to map an element to an actual class or type that is instantiated. Browsers will close your tags for you and even make substitutions for elements they don’t recognize. There are well-known algorithms for rendering HTML.

So how does this fit into MVC? First, let’s be clear on one important distinction:

MVC as a Framework, not a Pattern

Note I didn’t say MVC is a framework, but in the context of this conversation we’ll have to agree that I’m referring to MVC as a Microsoft Framework and not the pattern. When you talk about the pattern, it can get very confusing when introducing an entirely separate pattern like MVVM. When you talk about a framework based on the pattern, it’s a little easier to understand. While ASP. NET MVC is based on the MVC pattern, it doesn’t force a strict implementation or interpretation of the pattern and provides quite a bit of flexibility with how you structure your pages. You can choose different view engines and write your code in different languages.

So what about MVVM in the MVC framework? One of the key problems I’ve found when dealing with MVC is markup that looks like this:

<div id="logoDisplay">                
   <% Html.RenderPartial("LogoControl"); %>            
</div>                      
<div id="menuContainer">
   <ul id="menu">
      <li><%: Html.ActionLink("Home", "Index", "Home")%></li>
      <li><%: Html.ActionLink("About", "About", "Home")%></li>
   </ul>                       
</div>

What’s wrong with this? It compiles and runs perfectly fine, right? Here’s my issue: I’ve just lost my designer-developer workflow. True, I might be able to hire an MVC-savvy designer who can work with this code, or I may be responsible for design myself. I’ve seen this workflow before:

  1. Designer creates Adobe Photoshop assets
  2. Same designer or someone else turns it into a beautiful HTML web page
  3. Developer has to rip out the HTML as best as they can and format it into the view and merge into CSS
  4. QA tester finds some strange nuance where a field wraps and unfortunately the designer doesn’t know how to fix it because their version works fine, it’s only in the runtime that it happens
  5. It turns out one of the embedded commands emitted some whitespace that the template didn’t account for and was causing the issue
  6. etc. etc. etc. .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

This also gives me no design-time experience. If HTML was real HTML without any embedded markup, I could just drag it into a browser and go to town. This is one place I start to see value with MVVM in MVC. I could do the same thing above, but make it look like this instead:

<div id="menuContainer">
   <ul id="menu">
      <li data-bind="foreach: menuItem">
         <span data-bind="text: name">Name</span>
      </li>     
   </ul>   
</div>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Now I’ve got clean HTML that I can hand to a designer. I can even pull it up in a browser and view it to get a preview. Only … there’s still a problem. Can you see it?

The Problem with Data-Bind

Remember how I mentioned that HTML is not XAML? HTML is not supposed to be arbitrarily extended as in the previous example. In fact, most editors will complain about the data-bind attribute because it’s not a valid, defined attribute. Sure, you’ll get away with it: browsers are notoriously forgiving when it comes to bad mark-up, but this is what I would call an invasive or intrusive way to mark up HTML. What would really be nice is if we could do this more cleanly and provide pristine HTML with CSS, then provide our behaviors, validations, etc. in a way that is design-time friendly and testable.

A Clean Approach

For my “clean” approach I decided to model a simple form. It allows for first name and last name, shows the name dynamically as it is edited, and only allows submission when both fields are entered. First, let’s take a look at the HTML. I’m confident I could pass this off to a designer and they could modify it to their heart’s content. The only requirement is that they honor my “contract” which is the specific ids I’ve assigned. We agree there is something called a first name and last name and that they should be consistently referenced as firstName and lastName – whatever else they want to change is up to them.

The full HTML is here:

<!DOCTYPE html>
<html lang="en">
   <head>
      <title>Example MVVM Form</title>
      <link rel="stylesheet" href="style.css" type="text/css" media="screen" />
      <script type="text/javascript" language="javascript" src="jquery-1.7.1.js"></script>
      <script type="text/javascript" language="javascript" src="knockout-2.0.0.js"></script>
   </head>
   <body>
      <h1>Example MVVM Form</h1>
      <p>This is an example of an MVVM-based form. The HTML is "clean" markup - there are no custom attributes, tags, or embedded JavaScript. Everything is wired separately through code.</p>
      <form id="mainForm" action="#">
         <div class="form-label">Full Name:</div>
         <div class="form-field"><span id="fullName"></span>&nbsp;</div>
         <div class="form-label">First Name:</div>
            <div class="form-field">
               <input id="firstName" class="textField" type="text"/>
               <span id="firstNameValidation" class="field-validation"></span>
            </div>
         </div>
         <div class="form-label">Last Name:</div>
            <div class="form-field">
               <input id="lastName" class="textField" type="text"/>
               <span id="lastNameValidation" class="field-validation"></span>
            </div>
         </div>
         <input type="submit" class="formButton" value="Save">
      </form>
      <script type="text/javascript" language="javascript" src="./viewModel.js"></script>
      <script type="text/javascript" language="javascript" src="./mvvm.validations.js"></script>
      <script type="text/javascript" language="javascript" src="./bindings.js"></script>
   </body>
</html>
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Now that we have a page we can easily edit, let’s make it a little prettier with some simple CSS:
body {
    font-family: arial, helvetica, sans serif;
}

h1 {
   color: maroon; font-size: 20pt; font-weight: bold;
}
p {
   font-size: 12pt; 
}
.form-label {
   font-weight: bold;
   float: left;
   width: 200px;
   padding: 10px; 
}
.form-field {
   padding: 10px;
}
input.textField {
   width: 300px;
}
input.formButton {
   width: 100px;
   background-color: lightgreen;
   border: 2px solid green;
}
input.formButton:hover {
   background-color: lightred;
   border: 2px solid red;
}
.field-validation {
   font-weight: bold;
   padding-left: 10px;
   color: red;
}

The view model is easy enough, it simply defines fields for the first and last names and a computed field that shows the full name. I’ve even been kind enough to humbly supply a default first name:

function NameViewModel() {

   var self = this;

   this.firstName = ko.observable('Jeremy');
   this.lastName = ko.observable('');

   this.fullName = ko.computed(function() {
      if (self.lastName()) {
         if (self.firstName()) {
            return self.lastName() + ', ' + self.firstName();
         }
         return self.lastName();
      }
      return self.firstName();
   });
}

var viewModel = new NameViewModel();

What’s nice about the MVVM approach is that I can easily extend the view model to provide validation. I will eventually use the JavaScript module pattern to create the validations so they can be easily attached and extended, but for this simple example I just used a simple object instead. In this case there is simply a required validation. In a full production system, I would have a library of these validations and also keep a collection on the target object to allow multiple validations to attach to the same attribute.

ko.extenders.required = function (target, overrideMessage) {
    
    target.hasError = ko.observable();
    target.validationMessage = ko.observable();

    function validate(newValue) {
        target.hasError(newValue ? false : true);
        target.validationMessage(newValue ? "" : 
             overrideMessage || "This field is required.");
    }

    validate(target());
    target.subscribe(validate);
    return target;
};

function MvvmValidations() {
    
    this.required = function(target, overrideMessage) {
        target.extend({ required: overrideMessage });
    };

}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Now I have a view model specific to my view and a validation library that I can reuse across multiple views. I tie them all to the HTML like this – note that what is important is that the contracts were honored for the identifiers of the various elements, but everything else can be simply attached and declared.

$(document).ready(function() {

   $('#firstName').attr('data-bind','value: firstName, valueUpdate: "afterkeydown"');
   $('#lastName').attr('data-bind','value: lastName, valueUpdate: "afterkeydown"');
   $('#fullName').attr('data-bind', 'text: fullName');
 
   var validations = new MvvmValidations();

   validations.required(viewModel.firstName);
   $('#firstNameValidation')
   .attr('data-bind','visible: firstName.hasError, text: firstName.validationMessage');

   validations.required(viewModel.lastName, "Last name is required."); 
   $('#lastNameValidation')
   .attr('data-bind','visible: lastName.hasError, text: lastName.validationMessage');

   viewModel.saveName = function() {
      if (viewModel.firstName.hasError() || viewModel.lastName.hasError()) {
         alert('Errors exist.'); 
         return false;
      }
      alert('Looks good!');
      return true;
   };

   $('form').attr('data-bind', 'submit: saveName'); 
 
   ko.applyBindings(viewModel);

});

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

You can view the end result and download the source here: http://apps.jeremylikness.com/samples/knockout-mvvm/mvvm.html

Quod Erat Demonstrandum

So what have we achieved? I think quite a bit. This format has allowed me to build out a website using data-binding. The source HTML is clean and can be edited easily by a designer. While I muck around with the DOM at runtime, this is done programmatically and doesn’t require that I invade the HTML or CSS. The JavaScript is separate, reusable, and testable.

The thing I haven’t shown is how this fits into the MVC framework. In the framework you’ll likely go ahead and use some of those helper methods to specify the path to the JavaScript but you should be able to maintain a nice, clean HTML core. And if the view models seem like a lot of work, you’re not thinking about the bigger picture. With a strongly-typed view (one that correlates to a typed model) you can easily create a view helper that emits the necessary JavaScript for the view model. You could probably even emit the code to generate the bindings, and the only step you would need to take as a developer would be to write the controller to return the model and apply any validates specific to the view.

At the end of the day, I’m a believer that MVVM can work in MVC if we remember that HTML is not XAML and approach the code the right way.

I created a quick video to help you get started with using Jounce. The video starts with a blank slate, steps through installation of Jounce and the creation of a sample view model for a simple contact record that includes validation.

You can access the video directly at http://vimeo.com/jeremylikness/jounce-getting-started, or view it below:

Jounce: Getting Started from Jeremy Likness on Vimeo.

Jeremy Likness

I'm pleased to announce the official release of Jounce 2.0 for Silverlight 5. There are quite a number of new features available that I'll review in this post. Most significantly, of course, the code base has been updated specifically to target Silverlight 5. A number of bug fixes, feature requests, and Silverlight 5 features have been added. The DLL for Jounce is still just under 100 KB for release so it remains nimble and lightweight.

There are two ways you can install the latest. Zip over to Jounce at CodePlex to download the binaries and/or the full source. Or, jump into NuGet and install the Jounce package. The package is set up to wire in a default application. To get this functionality, follow these simple steps:

  1. Create a new Silverlight application. I recommend the basic "Silverlight Application" template as I haven't tested with any others, and it doesn't matter if you host it in a web site and/or choose to use WCF RIA services.
  2. Delete the App.xaml and MainPage.xaml files. Trust me on this one.
  3. Jump into the package manager console and type Install-Package Jounce.
  4. Hold down CTRL and press F5 and you should see a welcome message. That's it. You are ready to write your Jounce application.

What's New

The code base is now CLS compliant.

The application service used to wire Jounce now exposes some configuration properties. You can use this to have Jounce ignore unhandled exceptions (by default, it will intercept these and publish them as a message instead) and also to set the debug level. These used to be parsed from the parameters from the object tag but obviously this did not make sense for OOB applications.

When dynamically loading XAP files (i.e. extension or plugin modules) you can specify a callback that Jounce will call to report progress. This allows you to have more control over the extension points and display a progress message to the end user for example.

The processing of the XAP file URL was updated to allow query strings. This is a common method to dynamically serve up XAP files and/or to manage updates for OOB applications. Jounce used to choke on this but the code was updated to gracefully handle this when you specify the URL to the XAP to download.

You no longer have to derive your view model from the BaseViewModel class. The only requirement for the framework to work is for you to implement the IViewModel interface. This will help developers who wanted to provide their own base class services and found it difficult due to the face you cannot derive from more than one base class (hey, I managed to sneak in a basic interview question).

You can specify an option using metadata to automatically call Deactivate on your view model when the corresponding view is unloaded (i.e. if the Unloaded event fires). This allows you to perform clean up automatically when the view goes out of scope.

You can now map a view to a view model in three ways. You can export a ViewModelRoute, you can fluently bind them using a new interface, and you can specify the view model in XAML. The new MapToViewModel custom markup extension allows you to specify the view model name, whether you want a shared or non-shared copy, and whether the Deactivate method should be called when the view is unloaded. This makes it possible to use templates that bind to new instances of view models.

There is additional support for the OOB windows. You can append parameters to the navigation payload or use some fluent extension methods to specify the title and size of a view and have it loaded into a separate window instead of a region. You can also raise events with a title to set the title of the HTML page (in browser) or OOB application (out of browser). To further support OOB, there are additional attributes you can query on the base view model to determine if the application is running out of browser and whether or not it is installed on the user machine.

There is a new class available called CustomType that allows you to construct a dynamic type that is bindable to view models. For example, you might parse a JSON object and use this type to build up the object. It features methods to add new properties and fetch them and will also act as a dictionary with an indexer. It uses an underlying helper class that takes advantage of Silverlight 5's ICustomTypeProvider. You can use the source as a template to build your own custom types (or derive from it instead).

I will update documentation and examples as I can moving forward. My book, Designing Silverlight Business Applications, has many examples of building applications using Jounce including WCF RIA. Thanks everyone for their patience and support of this project!

Jeremy Likness

Jounce is the result of building composite Silverlight enterprise applications for a variety of verticals since Silverlight 3.0 and finding the common problems that needed to be solved. I found many frameworks to be too heavy for the task and always wondered why more did not tap into the native advantages that the Managed Extensibility Framework brings. So, I began porting my framework around as a core engine for projects and finally decided to make it available to provide guidance for building these types of applications using the MVVM pattern and MEF.

You can see concepts about Jounce echoed in many of my posts, but the easiest way to summarize the post-release topics is to follow the jounce tag on this blog. While bits and pieces have been posted over time, probably the first comprehensive peek at what Jounce would look like happened as the result of my 2010 CodeStock presentation. I posted an application called XFit to demo a live modular application that was more than just a button and a text file. Over time that has been refined and advanced through input from the community as well as fellow developers who are using Jounce in their own projects.

I'd like to give special thanks to Page Brooks for giving Jounce a logo, adding tests, testing the heck out of it and also giving us a wonderful project template (available on the downloads page).

Anyway I hope this guidance finds you well, and provides a nice, lightweight set of examples and patterns for building Silverlight applications with the MVVM pattern and MEF. Go ahead and grab the source, read the docs, and join the discussions at the Jounce CodePlex site. Thanks!

Jeremy Likness

This is a quick walkthrough to demonstrate how to make what I call "clean" design-time view models. These are view models that provide design-time data for your application, but don't embed that data in the final product. The release DLL and XAP files will only contain run-time support.

First, fire up Visual Studio and create a new Silverlight application. Just use the default template.

Keep all of the defaults on the dialog that prompts for hosting the application in a new web site (leave this checked) and use Silverlight 4. There is no need to check the "RIA Services" box for this example. When you confirm the dialog, the default project is created for you.

Next, add a folder called "ViewModels."



In the ViewModels folder, add a new class named MainViewModel. Make it a partial class. Create a string property called "Name", an observable collection of strings called "Widget," and implement INotifyPropertyChanged. Here is the code for the view model:

public partial class MainViewModel : INotifyPropertyChanged 
{
    public MainViewModel()
    {
        Widgets = new ObservableCollection<string>();
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged("Name");
        }
    }

    public ObservableCollection<string> Widgets { get; private set; }

    protected void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

As you can see, it is a fully functional view model, and no design-time data has been included yet. Next add a special compiler symbol to allow switching from design mode to release mode. Right click on the Silverlight project and go to the properties tab. Click on the "Build" sub-tab, and add the "DESIGN" compiler symbol:

Next, add a class that extends the view model partial class. Name it MainViewModel.sampledata.cs. Place this code in the file:

public partial class MainViewModel
{
#if DESIGN
    private void _WireDesignerData()
    {
        if (!DesignerProperties.IsInDesignTool) return;

        Name = "This is a design-time name.";
        var widgets = new[] { "Widget One", "A Second Widget", "The Third and final Widget" };
        foreach (var widget in widgets)
        {
            Widgets.Add(widget);
        }
    }
#endif
}

Notice the use of the compilation symbol that was added earlier. When you save the file, your solution should look like this:

Wire the call to the new method from the main view model class, wrapping it in the conditional tag - you may have to compile first to get Intellisense for the design-time method:

public MainViewModel()
        {
            Widgets = new ObservableCollection<string>();
#if DESIGN
            _WireDesignerData();
#endif
        }

Build the solution so the view model is available for wiring into the designer surface. Finally, go into the MainPage.xaml and add a grid and a list box bound to the view model. Be sure to add the namespace for your view model:

xmlns:ViewModels="clr-namespace:DesignFriendlyExample.ViewModels" mc:Ignorable="d"

Then wire the remaining XAML:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.DataContext>
        <ViewModels:MainViewModel/>
    </Grid.DataContext>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="{Binding Name}"/>
    <ListBox Grid.Row="1" ItemsSource="{Binding Widgets}"/>
</Grid>

You should immediately see the design-time data appear in the designer:

You can now design with designer data. If you compile and run the application, you'll see the page is blank because the design-time data only is populated in the designer. The only problem is that the XAP and DLL right now are "dirty." If you look at the DLL generated and open it using ILDASM this is what you'll find:

The design-time data has made the DLL larger by adding extra methods and text literals to load into the view models, and adds code that is not used in the run time. When you are ready to release your Silverlight application, simply go back to the properties for the Silverlight project and remove the "DESIGN" compilation symbol. Rebuild the project - it will build and run fine. However, if you take a look at the generated DLL now, the design-time data is no longer there and the DLL is smaller because the data has not been included - as you can see, the method to wire the data doesn't event exist on the view model:

Obviously this example worked with a very specific way of adding the view model to the view. Different frameworks have different ways of binding views and view models. This walkthrough should give you an idea of how to keep te design-time data separate regardless of the method you use and produce cleaner applications when design-time data is no longer needed.

Jeremy Likness

I'm exploring the phone more and more and came across the case of allowing the user to enter digits. One thing to keep in mind on the phone is that the form factor requires approaches to input that are different from the traditional desktop. A desktop application might handle numeric entry by simply filtering the text box, but that assumes a keyboard-centric model. On the phone, touch is key.

Of course, at the most basic level we could simply define an input scope on the phone and the SIP would give the user a number-friendly keyboard:

<TextBox Text="{Binding Weight,Mode=TwoWay,Converter={StaticResource DoubleConverter}}" 
    Grid.Row="1">
    <TextBox.InputScope>
        <InputScope>
            <InputScopeName NameValue="Digits"/>
        </InputScope>
    </TextBox.InputScope>
</TextBox>

With those hints in place, you will get a keyboard like this:

Numeric SIP on Windows Phone 7

It still isn't easy to hit the numbers and you will still have to validate the field. You could also use a slider like the infamous date control (I'll let you explore that one for yourself) but it's not the ideal experience. In fact, I thought about my favorite experience entering numbers on the phone and it had to be this:

Windows Phone 7 Calculator

Yes, it's the calculator. It's clean, easy, and famliar. So, I decided to build a control to allow a calculator-like experience for entering numbers.

Sample Data for the Control

I decided to go with a view model based control only because the application I'm working on uses both the Windows Phone 7 database called Sterling and my miniature MVVM framework called UltraLight.mvvm. This could easily use code-behind and dependency properties to be more "independent" but this approach is fine for me to build into my applications.

The interfaces for mocking and developing against are simple: a number that displays on the screen and a set of commands to enter digits, save, or cancel.

public interface INumberPadViewModelBase
{
    string Number { get; }
}

public interface INumberPadViewModel : INumberPadViewModelBase, IViewModel
{
    void SetValue(double value, string callbackTag);
    IActionCommand<object> DigitCommand { get; }
    IActionCommand<object> AcceptCommand { get; }
    IActionCommand<object> CancelCommand { get; }
}

My design-time view model just provides a little piece of pi:

public class DesignNumberPadViewModel : INumberPadViewModelBase 
{
    public string Number
    {
        get { return "3.1415"; }
    }
}

The View

This gives me enough to design the view. For this, I went with a fluid layout and mirrored the positions of the numbers on the calculator. Eventually I should probably replace the "delete" key with the backspace symbol, but for now the following layout gave me the digits and number display along with confirm and cancel options:

<Grid x:Name="LayoutRoot" 
        d:DataContext="{d:DesignInstance design:DesignNumberPadViewModel, IsDesignTimeCreatable=True}"
        Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <TextBlock Text="{Binding Number}" HorizontalAlignment="Right" FontSize="72" Margin="5"/>
        
    <Grid Grid.Row="1" HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <Button Grid.Row="0" Grid.Column="0"
                MVVM:ButtonCommand.Command="{Binding DigitCommand}"
                MVVM:ButtonCommand.CommandParameter="7">
            <Button.Content>
                <TextBlock Text="7" FontSize="56"/>
            </Button.Content>
        </Button>
        // lots of buttons omitted here 
        <Button Grid.Row="3" Grid.Column="0"
                MVVM:ButtonCommand.Command="{Binding DigitCommand}"
                MVVM:ButtonCommand.CommandParameter="0">
            <Button.Content>
                <TextBlock Text="0" FontSize="56"/>
            </Button.Content>
        </Button>
        <Button Grid.Row="3" Grid.Column="1"
                MVVM:ButtonCommand.Command="{Binding DigitCommand}"
                MVVM:ButtonCommand.CommandParameter="del">
            <Button.Content>
                <TextBlock Text="DEL" FontSize="56"/>
            </Button.Content>
        </Button>
        <Button Grid.Row="3" Grid.Column="2"
                MVVM:ButtonCommand.Command="{Binding DigitCommand}"
                MVVM:ButtonCommand.CommandParameter="dot">
            <Button.Content>
                <TextBlock Text="." FontSize="56"/>
            </Button.Content>
        </Button>
        <Button Grid.Row="4" Grid.ColumnSpan="3"
                MVVM:ButtonCommand.Command="{Binding DigitCommand}"
                MVVM:ButtonCommand.CommandParameter="clear">
            <Button.Content>
                <TextBlock VerticalAlignment="Center" Text="CLEAR" FontSize="56"/>
            </Button.Content>
        </Button>
    </Grid>        
</Grid>

As you can probably tell from looking at this, we have our "upper display" and the rest is simply a bunch of buttons bound to the same command. The digits pass the digit pressed, while the delete, clear, and decimals pass special text snippets that will be processed by the view model. In the designer, the number pad looks like this:

Number pad in the Windows Phone 7 Designer

The View Model

Now it's time to build the view model. I wanted to make it tombstone-friendly and because I'm using the MVVM framework, I decided to use messaging to transmit the number when the user confirms. First, I created a message to send:

public interface INumberPadResult
{
    string CallbackTag { get; }
    double Result { get; }
}

The result is self-explanatory. What about the callback tag? This is where it gets interesting. I'll be using a control to handle the numeric input. It will essentially pop out to the number view and then return back. This presents an interesting challenge with tombstoning because the control to return to isn't created yet (when the tombstone returns to the number pad, as I did not implement it as a pop-up) so there is nothing to listen for the value. Instead, the view model will have to pick it up.

Therefore, I decided to use the built-in Tag property to give the text box a unique name, and let the number pad share the tag value when transmitting the result. You'll see in a minute how that ties together.

The basic view model implements a few interfaces and defines constants for the "commands" such as delete and clear. I also decided to keep the digits as a simple array so I use a static array as the "initial value".

public class NumberPadViewModel : BaseViewModel, INumberPadViewModel, INumberPadResult, ITombstoneFriendly
{
    private const string DOT = "dot";
    private const string CLEAR = "clear";
    private const string DELETE = "del";
    private bool _navigating;

    private int _pos;
    private string[] _number = new string[10];

    private static readonly string[] _init = new[]
                                    {
                                        "0", string.Empty, string.Empty, string.Empty, string.Empty, string.Empty,
                                        string.Empty, string.Empty, string.Empty, string.Empty
                                    };
        
    public NumberPadViewModel()
    {
        DigitCommand = new ActionCommand<object>(o => _ProcessDigit((string) o), o => _CanProcess((string) o));
        AcceptCommand = new ActionCommand<object>(o => _ProcessResult());
        CancelCommand = new ActionCommand<object>(o => _Cancel());
        _init.CopyTo(_number, 0);
    }
}

You can see some commands are wired up and the array for the numbers is initialized. Here are the properties on the view model:

public override IEnumerable<IActionCommand<object>> ApplicationBindings
{
    get { return new[] {AcceptCommand, CancelCommand}; }
}

public bool HasDecimal
{
    get
    {
        return (from n in _number where n == "." select 1).Any();
    }
}

public string CallbackTag { get; set; }

public string Number
{
    get { return string.Join(string.Empty, _number); }            
}

public double Result { get; set; }        

public IActionCommand<object> DigitCommand { get; private set; }
public IActionCommand<object> AcceptCommand { get; private set; }
public IActionCommand<object> CancelCommand { get; private set; }

To make it easy to set up the number pad, I created a method (you saw that in the interface defined earlier) to load it with the initial information:

public void SetValue(double value, string callbackTag)
{
    CallbackTag = callbackTag;

    // remove any prior saved values
    PhitDatabaseService.Database.Delete(typeof(ValueModel), GetType().FullName);

    _init.CopyTo(_number, 0);

    // parse digits

    if (value != 0)
    {
        var digits = value.ToString();

        if (digits.Length > 10)
        {
            digits = digits.Substring(0, 10);
        }

        for (var x = 0; x < digits.Length; x++)
        {
            _number[x] = digits.Substring(x, 1);
        }

        _pos = digits.Length;
    }
    else
    {
        _pos = 0;
    }

    RaisePropertyChanged(()=>Number);
    DigitCommand.RaiseCanExecuteChanged();

    _navigating = true;
}

The processing commands handle disabling the delete key when there is nothing to delete and the decimal key when one has already been entered, and here I picked an arbitrary length of 10 ... obviously a more reusable control will have that exposed as a setting:

private bool _CanProcess(IEquatable<string> s)
{
    if (s.Equals(DOT))
    {
        return !HasDecimal;
    }

    if (s.Equals(DELETE))
    {
        return _pos > 0;
    }

    if (s.Equals(CLEAR))
    {
        return true;
    }

    return _pos < 10;
}

private void _ProcessDigit(string s)
{
    if (!_CanProcess(s)) return;

    if (s.Equals(DOT))
    {
        _number[_pos++] = ".";                
    }
    else if (s.Equals(DELETE))
    {
        _pos--;
        _number[_pos] = _pos == 0 ? "0" : string.Empty;                
    }
    else if (s.Equals(CLEAR))
    {
        _init.CopyTo(_number, 0);
        _pos = 0;
    }
    else
    {
        int digit;
        if (int.TryParse(s, out digit))
        {
            _number[_pos++] = s;
        }
    }

    RaisePropertyChanged(() => Number);
    DigitCommand.RaiseCanExecuteChanged();             
}

The processing just loads the digits into the array and stops allowing the decimal once it is entered.

Here are the save and cancel commands. The control implements the message payload interface so it is able to pass itself. Both actions will clear the call back tag, delete the tombstone entry and go back to the screen that it was called from:

private void _ProcessResult()
{
    Result = double.Parse(string.Join(string.Empty, _number));
    UltraLightLocator.EventAggregator.Publish<INumberPadResult>(this);
    _Cancel();
}

private void _Cancel()
{
    CallbackTag = string.Empty;
    PhitDatabaseService.Database.Delete(typeof(ValueModel), GetType().FullName);
    GoBack();
}

The last piece is to handle tombstoning. I have a value model class that is simply a string-based key with an object value that allows me to save just about anything. In this case I create an array of the position, the digits, and the call back tag, and use that to save and load values. Sterling will simply parse whatever is provided in the object parameter. Notice if I am navigating in from another screen (that field is set in the SetValue method) I won't clear the results but just pass through.

public void Deactivate()
{
    var value = new ValueModel { Key = GetType().FullName, Value = new object[] { _pos, _number, CallbackTag } };
    PhitDatabaseService.Database.Save(value);
}

public void Activate()
{
    var value = PhitDatabaseService.Database.Load<ValueModel>(GetType().FullName) ?? new ValueModel();
    if (value.Value is object[])
    {
        var tuple = value.Value as object[];
        _pos = (int)tuple[0];
        _number = (string[]) tuple[1];
        CallbackTag = (string) tuple[2];
    }
    else
    {
        if (_navigating)
        {
            _navigating = false;
        }
        else
        {
            _pos = 0;
            _init.CopyTo(_number, 0);
        }
    }
    DigitCommand.RaiseCanExecuteChanged();
    RaisePropertyChanged(()=>Number);
}        

That's it for the number pad.

The Numeric Textbox

We need a way to get to the number pad. The experience I think makes sense is to show the field on the screen as an editable field. However, when the user touches the field to begin editing, they are taken to the number pad. There, they can clear, edit, cancel, or confirm the value. To handle this I created the NumericTextBox control to work in conjunction with the number pad. When it is loaded, it walks up the tree to the parent page to get to the navigation context so it can call out to the number pad view when needed.

public class NumericTextBox : TextBox
{
    private NavigationService _navigation;
        
    public NumericTextBox()
    {
        MouseLeftButtonUp += _NumericTextBox;
        LostFocus += (o, e) => IsEnabled = true;
        GotFocus += (o, e) => IsEnabled = false;

        Loaded += _NumericTextBoxLoaded;
    }
        
    private void _NumericTextBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
    {
        Loaded -= _NumericTextBoxLoaded;

        var parent = VisualTreeHelper.GetParent(this);
        while (parent != null)
        {
            if (parent is PhoneApplicationPage)
            {
                _navigation = ((PhoneApplicationPage) parent).NavigationService;
                break;
            }
            parent = VisualTreeHelper.GetParent(parent);
        }            
    }

    private void _NumericTextBox(object sender, System.Windows.RoutedEventArgs e)
    {
        IsEnabled = false;
        var value = GetValue(TextProperty) as string;
        double valueParsed;
        if (!double.TryParse(value, out valueParsed))
        {
            valueParsed = 0;
        }
        UltraLightLocator.GetViewModel<INumberPadViewModel>().SetValue(valueParsed, Tag.ToString());
        _navigation.Navigate(new Uri("/Controls/NumberPad.xaml", UriKind.Relative));
    }        
}

The first thing it does is stay enabled until focused, then disables so the user doesn't accidentally enter text using the SIP. Next, when the mouse left button event is fired (which is a simple tap on the phone) it copies the value in the text property to the view model, sets the tag, and navigates to the number pad.

Remember, we need the tag to listen for the right value when the user confirms, so I set up the weight text box like this:

<Controls:NumericTextBox 
    Tag="WeightMessage"
    Text="{Binding Weight,Mode=TwoWay,Converter={StaticResource DoubleConverter}}" 
    Grid.Row="1"/>   

Notice that it is bound without any regard to the number pad - there is no knowledge in the view other than the control reference. It is bound to an actual property on the view model and the double converter simply converts from text to double and back. The last step is for the view model to listen for the tag. In this case, I added the tag directly. If you think this is too much of a "magic string" you can bind the tag to the view model as well, and use that when referencing the message.

The main view model implements IEventSink<INumberPadResult> to receive the message. The method looks like this:

public void HandleEvent(INumberPadResult publishedEvent)
{
    if (publishedEvent.CallbackTag.Equals("WeightMessage"))
    {
        Weight = publishedEvent.Result;
        return;
    }

    if (publishedEvent.CallbackTag.Equals("HeightMessage"))
    {
        Height = publishedEvent.Result;
        return;
    }
}

Again, here is where you could have a local value instead that is databound to avoid the magic strings. Now the control is complete. The screen renders like this:

Sample screen asking for weight and height

When you tap on one of the fields for entry, the number pad is popped up like this, making it very easy to enter your numeric value:

Number pad for Windows Phone 7

Of course, I could shade it like the calculator, add some more filters, etc. but for now it's a working control that is also 100% tombstone-friendly.

Jeremy Likness

I recently released a new open source project called simply UltraLight.mvvm. The purpose of this project is to make it easier to build MVVM-based applications that support tombstoning (a must) on Windows Phone 7. The DLL is 22KB and the source is less than 300 lines of code.

With that, the framework supports:

  • Commands
  • Command binding for buttons (with parameters)
  • Support for binding commands to application buttons on the application bar
  • Dialogs, both notification and confirmation
  • Messaging using the event aggregator publisher/subscriber model
  • Service location
  • Design-time friendly view models
  • Tombstone-friendly view models with control hooks for tombstone events
  • Decoupled navigation support from the view model
  • Decoupled visual state support from the view model
  • Notify property changed using expressions instead of magic strings
  • Dispatcher helper for UI thread access

Why not Jounce?

I think Jounce is overkill for the phone. Jounce specifically and explicitly relies on the Managed Extensibility Framework which is a phenomenal tool for building modular line of business applications for Silverlight. While the phone is Silverlight, and while there are certainly business applications on the phone, there are several reasons why I think it requires a completely different framework. These include:

  • The importance of the back button behavior that creates a very tight coupling to the navigation framework that is built-in
  • The fact that the applications are never launched from the web, but always executed as a first-class application on the phone
  • The limited resources available on the phone
  • The lack of certain key features that MEF leverages such as Reflection.Emit on the phone
  • The unique requirements created by tombstoning

For this reason, I wanted something quick and easy that would get me 90% of the way without much fuss. That's what this framework is.

I created a sample application to demonstrate the use of the framework. The application is bundled with the source and of this writing there is not a formal release, only the source with two projects: the framework itself and a sample phone application. You can download this from the CodePlex site.

Ultra Light MVVM Framework for Windows Phone 7

Getting Started: View Models

The first step is the view model. Some people won't like this but I created an interface with the "base" properties for the view model that I can use for my design, and then another interface that includes the framework's IViewModel to apply to the runtime. Why won't everybody like this? Because it really ends up being an empty interface that intersects two other interfaces. However, it makes it easier to build my design view model without having to stub out properties in the base view model that the designer doesn't need. Here are the interfaces:

public interface IMainBase
{
    string Text { get; }

    IActionCommand<object> EventCommand { get; }

    IActionCommand&t;object> StateCommand { get; }

    IActionCommand<object> DialogCommand { get; }

    IActionCommand<object> NavigateCommand { get; }
}

public interface IMainViewModel : IMainBase, IViewModel
{
        
}

With that, I can create a design-time view model with stubbed out properties:

public class DesignMainViewModel : IMainBase 
{         
    public string Text
    {
        get { return "This is some design-time text."; }
    }

    public IActionCommand<object> EventCommand { get; set; }

    public IActionCommand<object> StateCommand { get; set; }
        
    public IActionCommand<object> DialogCommand { get; set; }

    public IActionCommand<object> NavigateCommand { get; set; }        
}

In this case I really only had to mock one thing, the text field. In the XAML for the main page, I can then reference the design view model using the design-time extensions like this:

<Grid d:DataContext="{d:DesignInstance design:DesignMainViewModel, IsDesignTimeCreatable=True}"/>

This will show up nicely in the designer. The rest of the layout is simple. I wrap a border and add some visual states to make the border red or yellow to show how the framework works with the Visual State Manager. I have a text box for you to enter text and show it bound both in the text box and in a text block. I have a button to change states, to send the text via the event aggregator, and to navigate to another page. Finally, there is an application button that allows you to "delete" (clear) the text after answering a dialog.

You can see the button/command binding in the button that changes the visual state - notice it passes the target state as a parameter:

<Button Grid.Row="4" Content="Red Border" 
        MVVM:ButtonCommand.Command="{Binding StateCommand}"
        MVVM:ButtonCommand.CommandParameter="RedBorder"
        HorizontalAlignment="Center"/>

ActionCommand and Changing States

Let's take a look at the view model and how this is implemented with the ActionCommand provided by the framework. The command to change the state is valid if a non-empty string is passed. The base class is wired to the visual state manager, so the view model can simply call the GoToVisualState method. The command is wired like this:

StateCommand = new ActionCommand<object>(
    s =>
        {
            GoToVisualState(s.ToString(), true);
            _lastViewState = s.ToString();
        },
    s=>s is string && !string.IsNullOrEmpty((string)s));

That's it - you can databind the command parameter, or, like I did, pass in a literal. When you click the button, the state is changed and you can see the transitions as it fades from one color to the next. I save the state for tombstoning - more on that later.

Binding the View Model

Of course, for that to work, the view model has to get bound. I don't mind a little code-behind to get the job done if it's straightforward and easy. First, in my application start up, I need to register the view model. I'm telling the framework to handle exactly one copy of my view model and give it back whenever I ask for it (if you want new ones, you can just create new ones - no problem there). When the application starts, I call a simple method that registers the view model:

private static void _RegisterViewModels()
{
    UltraLightLocator.Register<IMainViewModel>(new MainViewModel());
}

Now it is set up to return that instance anytime I ask for it.

The framework provides an extension method to binding the view model to the view. I decided to go with a method that would take a framework element. Some people won't like this, but I have a good reason. The binding can affect how the datacontext is propagated through the hierarchy, and some controls used as the "root" control can behave differently when they are bound too soon. By allowing the element to be passed, you have more control over where in the visual tree it is bound and how. Most often, you'll do what the example does and simply bind it to the root grid, often called LayoutRoot. Here is the code-behind for the main page:

public MainPage()
{
    InitializeComponent();
    this.BindToViewModel<IMainViewModel>(LayoutRoot);
}

That's it - I just pass the contract for the view model and the element to bind to. Behind the scenes, the framework will attach to the loaded event of that element and wait to actually data-bind until it is fully loaded. If you are working with a control like the pivot control, which will throw errors if you bind to it too soon, this will avoid that problem. It will also set up a delegate to call into the Visual State Manager, and wire in the navigation context so the view model can raise navigation events. When you bind to a user control, it will walk the visual tree to find the host page in order to grab a valid navigation context.

Navigation

That takes us to navigation. The navigation button fires a navigation command. The command is wired to call a method, and the method looks like this:

private void _Navigate()
{
    RequestNavigation("/SecondPage.xaml");
}

Just request navigation and pass the view. The framework handles casting this to a URI and then passing it to the navigation context. You can also call GoBack() to cancel or go to a previous page.

The Event Aggregator

I used the same code for the event aggregator that I use in Jounce as it is lightweight and robust. The command to send the event is wired to publish whatever text has been entered. It is set up like this:

EventCommand = new ActionCommand<object>(
    o => UltraLightLocator.EventAggregator.Publish(Text),
    o=>!string.IsNullOrEmpty(Text));

Notice how easy it is to send a message - just grab the instance for the aggregator and publish it. It can be any type. To receive a message, you simply implement IEventSink<T> where T is the type of message you want to listen for. In this case, the same view model also listens for its own message (hey, this is a demo, right?) You can see in the definition the IEventSink<string> which requires you to create a method that is called with the message.

To subscribe, you pass an instance of the class that has implemented the interface. Because this is set up for only one message, the type doesn't have to be specified as it can be inferred from the interface:

UltraLightLocator.EventAggregator.SubscribeOnDispatcher(this);

Notice you have the option to subscribe directly, or if you know you'll be interacting with the UI thread you can subscribe on the dispatcher and the method will be called from the UI thread. If you implement multple interfaces, you just indicate the type of message you are subscribing for like this:

UltraLightLocator.EventAggregator.SubscribeOnDispatcher<string>(this);

Dialogs

I created a simple interface to abstract the dialog mechanism. It takes a title, a message, and a boolean to determine if it is a notification (you can only click OK) or a confirmation (OK or Cancel). When the message is received, a notification is sent in the receiving method:

public void HandleEvent(string publishedEvent)
{
    Dialog.ShowMessage("Received Text", publishedEvent, false);
}

Application Button Binding

One aspect of the phone I don't like is the fact that the application buttons are not directly bindable. There are some interesting solutions there but I decided to just make it simple: if you specify three buttons, return an array of three commands that map to the buttons. In this case, we have a "delete" button that clears the text field. It only makes sense to call it if there is text, so the command is set up like this:

DialogCommand = new ActionCommand<object>(
    o => _RequestDelete(),
    o => !string.IsNullOrEmpty(Text));

The delete request uses the dialog as well, this time to confirm the request:

private void _RequestDelete()
{
    if (Dialog.ShowMessage("Confirm Delete","Click OK to Clear the Text.", true))
    {
        Text = string.Empty;
    }
}

Finally, the command is bound to the button by returning it in the button bar list:

public override IEnumerable<IActionCommand<object>> ApplicationBindings
{
    get { return new[] { DialogCommand }; }
}

If you have nothing to bind, you can just return an empty list.

Tombstoning

The final element to cover is tombstoning support. The interface ITombstoneFriendly is provided to indicate the view model will explicitly support tombstoning. The pattern for tombstoning can be simplified to this:

  1. When tombstoned, save data
  2. When activated, load data
  3. When the application exits, clear the saved data so the application "starts fresh"

The tombstone interface provides two methods to save and then restore data. In the example, the text is saved, as well as the last view state. If you make the border red and tombstone, it will still be red when you return to the application. (Hint: using Sterling makes this a whole lot easier).

Here is the implementation of the interface for the sample application:

public void Deactivate()
{
    var settings = IsolatedStorageSettings.ApplicationSettings;
    settings["ViewState"] = _lastViewState;
    settings["Text"] = Text;
}

public void Activate()
{
    var settings = IsolatedStorageSettings.ApplicationSettings;
    if (settings.Contains("ViewState"))
    {
        _lastViewState = (string) settings["ViewState"];
        GoToVisualState(_lastViewState, false);
    }
    if (settings.Contains("Text"))
    {
        Text = (string) settings["Text"];
    }
}

Also, in the application object, when the application exits normally, I clear the settings:

private void Application_Closing(object sender, ClosingEventArgs e)
{
    var settings = IsolatedStorageSettings.ApplicationSettings;
    if (settings.Contains("ViewState"))
    {
        settings.Remove("ViewState");
    }            
    if (settings.Contains("Text"))
    {
        settings.Remove("Text");
    }
}

There is a special process to bind the view to the view model for the tombstone process. The code-behind for the main page adds two overrides that look like this:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    this.DeactivatePage<IMainViewModel>();
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    LayoutRoot.ActivatePage<IMainViewModel>();
    base.OnNavigatedTo(e);
}

Wiring these events causes the framework to cast the view model to ITombstoneFriendly and call the appropriate method. Notice that the deactivate command extends the page and uses this, but the activate command extends a framework element. Why is that? Once again, if you are using a pivot control or a panorama control, the navigation event happens before the control is fully loaded. Binding too soon will result in the controls throwing an exception. By extending from the element itself (i.e. if you use a pivot, you use the name of the pivot control instead of the layout root to call ActivatePage) the framework knows to wait for that element to load. Only when the element is loaded will it call the tombstone method. It will also dispatch this on the UI thread to queue it behind any pending requests, allowing for a seamless transition from the tombstoned state.

Conclusion

As you can see, it is a very small framework but does quite a bit. It's by no means a magic "pull the lever and I have a full blown Windows Phone 7" application, but I believe it is solid enough to help anyone hit the ground running and small enough that you can modify or extend it to fit your specific needs. I look forward to any feedback and suggestions.

Jeremy Likness

Yesterday I wrote about an ultra light Windows Phone 7 MVVM Framework and mentioned that I would deal with tombstoning in a later post. This is the post.

Sterling makes tombstoning very easy because it handles serialization of just about any type of object. To show an example, we'll start with the concept of a view model that holds a set of categories (that a pivot is bound to) and a set of items that are filtered by category. When tombstoned, the application must remember the category as well as any item that is selected.

Build the Tombstone

First thing to do is create the generic tombstone model to hold values. This is the model:

public class TombstoneModel
{
    public TombstoneModel()
    {
        State = new Dictionary<string, object>();
    }

    public Dictionary<string, object> State { get; set; }

    public T TryGet<T>(string key, T defaultValue)
    {
        if (State.ContainsKey(key))
        {
            return (T)State[key];
        }
        return defaultValue;
    }
}

But wait ... what's the point? Isn't that just like the application settings object? Sure ... sort of. There are a few problems with application settings. First, they don't handle complex object graphs and the objects must be serializable. They don't recognize things like "foreign keys" or sub lists. Second, they load into memory as opposed to isolated storage files which can be loaded on demand.

Sterling, on the other hand, can handle almost any type of object (and for the ones it can't handle, you can write a custom serializer).

Define the Tombstone Table

A full lesson on Sterling is outside the scope of this post. To learn about Sterling, read the User's Guide. To define a table in Sterling, you pass the type of the table and a key. Because there will only ever be one instance of the tombstone model, you cheat the key and make it always have a "true" value like this:

CreateTableDefinition<TombstoneModel,bool>(c=>true)

Finally, because the tombstone model is only to hold values that must be saved during a tombstone event, the model should be cleared when the application truly closes (as opposed to being deactivated due to a tombstone event). Therefore, in the Application_Closing method you can delete the tombstone model, if it exists:

private void Application_Closing(object sender, ClosingEventArgs e)
{
    Database.Delete(typeof (TombstoneModel), true);
}

Now everything is set to handle the tombstone properties.

Making your View Model a Caretaker

What other way is there to describe a view model that is "tombstone friendly?" To make a view model friendly, decorate it with the ITombstoneFriendly interface that looks like this:

public interface ITombstoneFriendly
{
    void Deactivate();
    void Activate();
}

These will be implemented in a moment.

Hooking into the Page

The best way to manage tombstone events is to hook into the OnNavigatedTo and OnNavigatedFrom overrides in the page code-behind. In fact, because forward navigation always generates a new instance of the view, this is the perfect way to maintain state of the view during navigation even when tomstoning isn't taking place.

Like before, we'll take advantage of some extension methods to make this easy. Here's a little caveat: you may be familiar with some "gotchas" with tombstoning if you've read Jeff Prosise's Real World Tombstoning series (here's part 2, part 3, and Part 4). Oh, and did you know that Sterling automatically serializes WriteableBitmaps using the "fast" technique Jeff describes in those posts? You can easily add one to the tombstone collection and it will serialize for you!

The issue with the pivot index happens due to the order of loading. If you restore values on the view model before the view is loaded, the view itself will reset any two-way bindings and you'll find a pivot simply snap to the first item. This is no good! Therefore, the extension method for the activate waits until the page is loaded, then calls the activate method on the view model.

Here are the extension methods:

public static void DeactivatePage(this PhoneApplicationPage phonePage, IViewModel viewModel)
{
    if (viewModel is ITombstoneFriendly)
    {
        ((ITombstoneFriendly)viewModel).Deactivate();
    }
}

public static void ActivatePage(this PhoneApplicationPage phonePage, IViewModel viewModel)
{
    RoutedEventHandler loaded = null;
    loaded = (o, e) =>
                    {                             
                        ((PhoneApplicationPage) o).Loaded -= loaded;
                        if (viewModel is ITombstoneFriendly)
                        {
                            ((ITombstoneFriendly) viewModel).Activate();
                        }
                    };
    phonePage.Loaded += loaded;
}

The loaded event doesn't take any conditional arguments, so it would be impossible to pass the view model to that event. Therefore, an anonymous method is used instead. By using a local variable, it can be unhooked inside the event call so it is not fired again. Once the page is loaded, the activate method is called on the view model. Because the page has been loaded, binding a pivot control item will work perfectly if the pivot SelectedItem is synchronized with a value on the view model.

Here's what the calls look like from the code-behind for the MainPage.xaml, hooking into the navigation events and passing the correct view model:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    this.ActivatePage(GlobalManager.GetViewModel<IMainViewModel>());
    base.OnNavigatedTo(e);
}
        
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    this.DeactivatePage(GlobalManager.GetViewModel<IMainViewModel>());
    base.OnNavigatedFrom(e);
}

Raising the Dead

The only thing left is to perform the actual deed. When the view model is flagged for death, it will hydrate out key values. In this case, it is the current category and current item:

public void Deactivate()
{
    var tombstone = new TombstoneModel();
    if (CurrentCategory != null)
    {
        tombstone.State.Add(ExtractPropertyName(() => CurrentCategory), CurrentCategory.Id);
    }
    if (CurrentItem != null)
    {
        tombstone.State.Add(ExtractPropertyName(()=>CurrentItem), CurrentItem.Id);
    }
    App.Database.Save(tombstone);
}

A new model is created because you never care about the old model - this is saving state for the current tombstone event, and the state from any other don't matter (they will be wiped when the application closes anyway). The dictionary is loaded with the key values for the current catalog and the current item.

Now when the application is revived:

public void Activate()
{
    var saved = App.Database.Load<TombstoneModel>(true);

    if (saved == null) return;

    var categoryId = saved.TryGet(ExtractPropertyName(() => CurrentCategory), 0);

    if (categoryId > 0)
    {
        CurrentCategory = (from c in Categories where c.Id == categoryId select c).FirstOrDefault();
    }
    var currentItemId = saved.TryGet(ExtractPropertyName(() => CurrentItem), 0);            
    if (currentItemId > 0)
    {
        CurrentItem = (from i in Items where i.Id == currentItemId select i).FirstOrDefault();
    }
}

In this case, the category list is always loaded in the constructor of the view model. That doesn't change regardless of tombstoning or not. The items is a filter by category, so when the category is updated, the items filter is also updated. When the old state is loaded, first the category is checked and if it exists, the current category is set to the corresponding category item. The same happens with the item.

That's it. When testing the application, going into a pivot page always returns to the correct pivot column, and the selection state of the list is always maintained. If the application is exited by backing out, the close event deletes the tombstone key and upon re-entering, the pivot and list start on the first page with no selection as expected.

Tombstoning with MVVM can be dead simple with a few helper methods and Sterling to serialize the data.

Jeremy Likness

I've been doing more work on Windows Phone 7 applications. Because of the smaller footprint of the phone and the way the application is hosted, I don't believe the phone requires the same types of tools and frameworks as the browser. Sharing code and services is something that is obviously important, but while I am a huge advocate of the Managed Extensibility Framework (MEF) and use it in my own Jounce MVVM Framework, I'm not convinced it is needed for smaller phone applications.

So how do I use MVVM on the phone? I'm still exploring options and admit I have not used some of the existing (and probably fantastic) frameworks that are out there. What I did notice immediately was that I would need about six key things to be successful on the phone:

  1. Notify Property Changed — a global requirement for MVVM
  2. Commands — this is fairly universal for data-binding in Silverlight
  3. Dialogs — again, common but easy on the phone
  4. Navigation — a decoupled way to use the phone navigation (not interested in rolling my own due to the stringent "back button behavior" requirements)
  5. Application Bar Bindings — need an effective/easy way to handle getting those icons bound to the view model
  6. Tombstoning — this is every Windows Phone 7 programmer's bane, I handle that with Sterling and will talk more about it later.

After working on a few applications, I came up with an extremely light weight framework that is working well for me, so I'm sharing it here. There is no sample project (I am working on one but it's for an upcoming article and not ready to release) but everything you need is here, in source.

Notify Property Changed

The first thing is to create a base class to handle property changed notification. This is almost verbatim the base class that I use in my Jounce framework. You can see the source for it here and it is pretty close to the code that the Prism framework provides in their MVVM guidance.

Commands

I also copied my command implementation, which is close to the DelegateCommand or perhaps RelayCommand implementations you are familiar with. Mine is IActionCommand and you can browse the interface source and implementation source.

A Common Contract

Next, a common contract for view models to address some of the other concerns. The contract looks like this:

public interface IViewModel
{
    IDialog Dialog { get; set; }
    Action<string> RequestNavigation { get; set; }
    Action GoBack { get; set; }
    IEnumerable<IActionCommand<object>> ApplicationBindings { get; }
}

Notice this gives us a decoupled baseline to deal with dialogs and navigation requests. It also returns a list of commands .. called application bindings? Hmmm. Interesting.

A Base Implementation

Next is the base view model, where I add a design attribute and placeholders for the rest:

public abstract class BaseViewModel : BaseNotify, IViewModel
{        
    protected bool InDesigner
    {
        get
        {
            return DesignerProperties.IsInDesignTool;
        }
    }

    public IDialog Dialog { get; set; }

    public Action<string> RequestNavigation { get; set; }

    public Action GoBack { get; set; }

    public abstract IEnumerable<IActionCommand<object>> ApplicationBindings { get; }
        
}

The dialog interface looks like this:

public interface IDialog
{
    bool ShowMessage(string title, string message, bool allowCancel);
}

Next comes the fun part. There may be a case for an inversion of control container here, but I'm going to follow a fairly common pattern but instead of shoving a bunch of variables into the App object, I'll create a GlobalManager class for the MVVM concerns. Now this is a static class and of course that concerns some people for becoming problematic down the road because the views will be tightly bound (plus it's one of those hated singletons). In this case it just doesn't bother me. I unit test the view models, not necessarily the views, and use design-time data in the views. Therefore, the binding for me doesn't pose a threat as I can still grab the view models and run them in isolation while mocking the interfaces.

I'll double the manager as a view model locator and just return a singleton instance of the view models. For data I'll use design time data based on sample data that implements a common view model interface. I'm basically following the pattern from Design-time Friendly View Models with MEF only without the MEF.

The first thing I'll do with my class is provide an extension method for pages to bind to the view model. This method will wire up the dialog and navigation, and also inspect the list of application bindings and wire those up as well. For the most part the view model doesn't need to know about the view, but this is one case where there is a slight dependency: the view model is responsible for knowing the order of the buttons in the application bar so it can return the commands in the correct order. The extension method will then bind the buttons to the commands. Here it is:

public static void BindToViewModel(this PhoneApplicationPage phonePage, FrameworkElement root, IViewModel viewModel)
{
    if (DesignerProperties.IsInDesignTool) return;

    RoutedEventHandler loaded = null;

    var vm = viewModel; // access to modified closure

    loaded = (o, e) =>
                    {
                        var page = o as PhoneApplicationPage;
                        if (page == null)
                        {
                            return;
                        }

                        // unhook loaded so we do this only once
                        page.Loaded -= loaded;

                        // provide an implementation for the dialog
                        vm.Dialog = new Dialog();

                        // provide an implementation for navigation
                        vm.RequestNavigation =
                            newPage => page.NavigationService.Navigate(new Uri(newPage, UriKind.Relative));
                        vm.GoBack = page.NavigationService.GoBack;

                        // bind the view model
                        root.DataContext = vm;

                        // bind the application bar buttons
                        var idx = 0;
                        foreach(var command in vm.ApplicationBindings)
                        {
                            if (page.ApplicationBar.Buttons.Count <= idx) break;
                                     
                            var appButton = page.ApplicationBar.Buttons[idx++] as ApplicationBarIconButton;
                                     
                            if (appButton == null) continue;
                            var command1 = command;
                            command.CanExecuteChanged += (cmd, arg) =>
                                                        appButton.IsEnabled =
                                                        command1.CanExecute(null);
                            appButton.Click += (cmd, arg) =>
                                            command1.Execute(null);
                        }
                    };

    phonePage.Loaded += loaded;
}

As you can see, we do a few things. A local variable hosts the delegate for the loaded event so we can unhook it when done. We link the navigation service from the page to the view model, and then iterate the application buttons. Basically, we do manually what command bindings do automatically, and that's change the enabled state of the button based on the command's ability to execute, and bind the click event to a command execution.

The View Model

What did we accomplish? First we get a view model that has a "save" and "cancel" action that looks like this:

public class MainViewModel : BaseViewModel, IMainViewModel
{
    public MainViewModel()
    {           
        SaveCommand = new ActionCommand<object>(o=>_SaveCommand(), o=>_CanSave());

        CancelCommand = new ActionCommand<object>(o=>_CancelCommand());        
    }                 
    
    public IActionCommand<object> SaveCommand { get; private set; }

    public IActionCommand<object> CancelCommand { get; private set; }

    private void _SaveCommand()
    {
        DoSave();        
        RequestNavigation("/Views/WidgetList.xaml");
    }

    private bool _CanSave()
    {
        return true; 
    }

    private void _CancelCommand()
    {
        if (!Dialog.ShowMessage("Confirm Cancel", "Are you sure you wish to cancel?", true)) return;
        GoBack();
    }

    public override IEnumerable<IActionCommand<object>> ApplicationBindings
    {
        get { return new[] {SaveCommand, CancelCommand }; }
    }
}

Notice the dialog call. Currently, I'm simply using the built-in dialog provided by the MessageBox function on the phone, but the interface allows you to implement it any way you like. Here is my implementation:

public class Dialog : IDialog 
{
    public bool ShowMessage(string title, string message, bool allowCancel)
    {
        return MessageBox.Show(message, title, allowCancel ? MessageBoxButton.OKCancel : MessageBoxButton.OK)
                == MessageBoxResult.OK;
    }
}

The View

Having done all of that, what does it take to actually bind the main page to the view model? Fortunately, with this framework, even using the application buttons and binding them to commands, this is the entire code-behind for the main page:

public partial class MainPage
{        
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        this.BindToViewModel(LayoutRoot, GlobalManager.MainViewModel);            
    }                        
}

The reference to the main view model is type IMainViewModel and is lazy created when referenced the first time.

For nested user controls, I created a similar extension method with the difference that it doesn't bind the buttons as there obviously isn't an application bar for a user control (the view model can just return an empty list or null). To allow the user control to affect navigation, the binding code simply walks the visual tree to the parent to grab the navigation service:

// hook to the navigation of the parent
var parent = VisualTreeHelper.GetParent(control);
while (parent != null)
{
    if (parent is PhoneApplicationPage)
    {
        vm.RequestNavigation =
            newPage => ((PhoneApplicationPage)parent).NavigationService.Navigate(new Uri(newPage, UriKind.Relative));
        vm.GoBack = ((PhoneApplicationPage) parent).NavigationService.GoBack;
        break;
    }
    parent = VisualTreeHelper.GetParent(parent);
}

As I mentioned, I'm still working on various applications to find out what other patterns present themselves, but this to me is a very simple, lightweight, and easy way to get started with the MVVM pattern on the phone.

Jeremy Likness

This will be a shorter bit for an interesting topic. I've noticed a few posts and discussion around raising the property changed notification. This continues to be the sore spot for MVVM. It creates quite a bit of ceremony for what is a fairly common piece of functionality that shouldn't be so hard to create.

Jounce supports all of the common ways of doing this, but there is a third that I learned from a colleague of mine (Keith Rome) that I added and think bears some attention.

The most common approach is to use the "magic string" technique (which many developers automatically cringe at) and do something like this:

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        RaisePropertyChanged("FirstName");
    }
}

The problem there of course is that it is too easy to type the property wrong. Coders who typically "cut and paste" might forget to update this and then they'll find themselves raising the wrong property.

The next iteration types the property a bit and gets rid of magic strings. It does this by allowing a lambda expression to be passed in. The expression tree is parsed and the property name is extracted. Some extra validation can even make sure it's inside a property - but there is still no guarantee you aren't raising the wrong property, you just know you are raising some property.

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        RaisePropertyChanged(()=>FirstName);
    }
}

So the third method is a little more safe. Not only does it avoid magic strings, but I can get out of the ceremony of passing a weird lambda expression, and I can guarantee it will raise the notification for the correct property. Before I talk about how this works, let me show you the code:

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        RaisePropertyChanged();
    }
}

This will throw an exception if it's not in a setter. And it will always capture the current property. I still have to make a call, but no magic strings and we've reduced the ceremony somewhat. How does it work?

The trick is the context of execution. All of these methods have a little overhead (the string method actually has the best performance) but in most applications if the performance hit is in your setters, you've probably got worse issues farther up the stack.

Speaking of the stack, that's exactly what we use. We simply walk the stack frames up from the setter to find the name of the setter method itself. The convention for properties is set_propName so we look up where we are at and grab the propName.

Here's the code:

public virtual void RaisePropertyChanged()
{
    var frames = new System.Diagnostics.StackTrace();
    for (var i = 0; i < frames.FrameCount; i++)
    {
        var frame = frames.GetFrame(i).GetMethod() as MethodInfo;
        if (frame != null)
            if (frame.IsSpecialName && frame.Name.StartsWith("set_"))
            {
                RaisePropertyChanged(frame.Name.Substring(4));
                return;
            }
    }
    throw new InvalidOperationException("NotifyPropertyChanged() can only by invoked within a property setter.");
}

Notice once we extract the property name, we just pass it along to the method that takes a happy string.

There you have it - another way to do the deed with a little more overhead but a lot less ceremony.

Jeremy Likness

I thought it might be useful for users (and potential users) of Jounce, MVVM, and Silverlight in general if I were to show the full process of building an application. When people ask me about how complicated MVVM is, I reply "it's easy when you know it and use the right framework." I hope this video illustrates that. I also find Silverlight in general to be an amazing technology because I can build a useful application so quickly. You'll see in the video I could have done it faster using short cuts, designer, etc. I am still waiting for someone to show me how to do the same thing in HTML5 in the same amount of time.

After recording this video, I noted two issues that have been corrected in the source and the example below. These would not impact the overall time but I did catch them only after I went live. Here are the fixes:

Text Update

In both FireFox and Chrome, hitting TAB won't advance from the text box properly as it does in IE, so the "GO" button never activated unless you clicked outside of the application. This is easily fixed by resetting the error state on a key press. In the XAML, I just wired a text change event:

<TextBox Grid.Column="1" Grid.Row="1" TextChanged="TextBox_TextChanged"...>

In the code-behind, I simply update the data-binding source:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    ((TextBox)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}

The view model then gets this tweak to clear the errors to enable the button (it will put the errors back if you click and there is a problem):

public string FeedUri
{
    get { return _feedUri; }
    set
    {
        _feedUri = value;
        RaisePropertyChanged(() => FeedUri);
        ClearErrors(() => FeedUri);
    }
}

Missing Summary

For some reason IE brings back summary information, but Chrome and Firefox do not from the feed. Therefore, I needed to add this little fix to avoid a null object reference exception when the summary information is missing:

Summary = ConvertHtml(item.Summary != null ? item.Summary.Text : string.Empty)

Finally, in the video I typed "encode" instead of "decode" on the http utility. These are the only changes to the source and example below from what you see in the video.


You can download the source code here.

The finished product is here:


Click here to view in a new window.

Enjoy!
Jeremy Likness

This is the second part in the post of more "fun" effects and challenges I worked through in Silverlight when building my personal web page.

One effect I really wanted to work out is the Matrix-style effect you can see on my blog page. After looking at the video I determined the main characters seemed to remain in a fixed position and it's the shading of them that creates the motion. I was able to create the effect using the MVVM model (I wasn't trying to force this, it just happened naturally) and storyboards - there is no timer or code behind involved as it is all done with XAML, data-binding, and the defined behaviors that create the storyboards.

Working from the bottom up, I first wanted to tackle having some random, funky characters. I knew that I would be handling "columns" of these, so I started with what a column would look like. The MatrixText class takes the size of the column and generates the characters for me, exposing them as a list of strings. I inherited from observable collection in case I wanted to manipulate the strings:

public class MatrixText : ObservableCollection<string>
{     
    private static readonly Random _random = new Random();        

    public Guid Id { get; private set; }

    public MatrixText() 
    {
        Id = Guid.NewGuid();
    }

    public MatrixText(int size) : this()
    {
        var bytes = new byte[size];
        _random.NextBytes(bytes);
        foreach(var c in bytes)
        {
            Add(new string((char)c, 1));
        }
    }

    public override bool Equals(object obj)
    {
        return obj is MatrixText && ((MatrixText) obj).Id.Equals(Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

Next, I created the MatrixStack class to hold any number of MatrixText to complete the grid. It also takes a constructor with the number of items, and then simply spins up a list. Keep in mind each element is automatically generating characters:

public class MatrixStack : ObservableCollection<MatrixText>
{
    public Guid Id { get; private set; }       

    public MatrixStack() 
    {
        Id = Guid.NewGuid();
    }

    public MatrixStack(int size, int textSize) : this()
    {
        var remaining = size;
        while (remaining-- > 0)
        {
            Add(new MatrixText(textSize));
        }
    }

    public override bool Equals(object obj)
    {
        return obj is MatrixStack && ((MatrixStack) obj).Id.Equals(Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

So now I can easily create the matrix of characters with a single class. Now I could build the view model, which exposes the matrix stack:

[ExportAsViewModel(Constants.VIEWMODEL_BLOG)]
public class BlogViewModel : BaseViewModel 
{
    private const string CSHARPER = "http://feeds.feedburner.com/csharperimage";

    public BlogViewModel()
    {
        Stack = InDesigner ? new MatrixStack(40, 20) : new MatrixStack(76, 70);
        Blog = new ObservableCollection<BlogEntryItem>();
        NavigateExternalProject = new ActionCommand<Uri>(_NavigateExternal);

        if (InDesigner)
        {
            Blog.Add(new BlogEntryItem
                            {
                                Link = new Uri("http://www.bing.com/", UriKind.Absolute),
                                Title = "This is a Sample Blog Entry of Mine",
                                Posted = DateTime.Now                                 
                            }
                );
            Blog.Add(new BlogEntryItem
                            {
                                Link = new Uri("http://www.bing.com/", UriKind.Absolute),
                                Title = "This is a Another Sample Blog Entry of Mine",
                                Posted = DateTime.Now                                 
                            }
                );
        }
        else
        {
            HelperExtensions.LoadResource(new Uri(CSHARPER, UriKind.Absolute), ParseBlog);  
        }
    }

    private static void _NavigateExternal(Uri target)
    {
        HtmlPage.Window.Navigate(target, "_blank");
    }

    public IActionCommand<Uri> NavigateExternalProject { get; private set; }

    private void ParseBlog(string feedSrc)
    {
        if (string.IsNullOrEmpty(feedSrc))
        {
            return;
        }

        try
        {
            var reader = XmlReader.Create(new StringReader(feedSrc));
            var feed = SyndicationFeed.Load(reader);
            JounceHelper.ExecuteOnUI(()=>{
            foreach (var feedItem in feed.Items)
            {
                Blog.Add(new BlogEntryItem
                                {
                                    Link = feedItem.Links[0].GetAbsoluteUri(),
                                    Posted = feedItem.PublishDate.Date,
                                    Title = feedItem.Title.Text,
                                    NavigateCommand = NavigateExternalProject
                                });
            }
            });           
        }
        catch(Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

    public MatrixStack Stack { get; private set; }

    public ObservableCollection<BlogEntryItem> Blog { get; private set; }
}

There are a few moving pieces here. The matrix is created and sized based on whether or not we are in the designer (a smaller matrix will be created at design time). I also have the list of blog entries and either populate these with sample data or use the extension helper I introduced in the last post to fetch the feed and parse it using the SyndicationFeed class.

That's it for the view model - it provides all of the binding I need to create the effect. It also has all of the code to download and parse the RSS feed from my blog.

The next thing I did was get the characters on the screen using binding. I used a combination of items controls, one for each column and another for each character:

<ItemsControl Margin="100 0 0 0" Opacity="0.6" ItemsSource="{Binding Stack}"> 
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <ItemsControl ItemsSource="{Binding}">
                    <Interactivity:Interaction.Behaviors>
                        <Behaviors:FreezeBehavior/>
                    </Interactivity:Interaction.Behaviors>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical"/>                                          
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding}" FontFamily="Consolas" FontSize="16" FontWeight="Bold" Foreground="LawnGreen"/>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
                <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                            Margin="0 -800 0 0"
                            Fill="Black">
                    <Rectangle.RenderTransform>
                        <ScaleTransform ScaleY="2.0"/>
                    </Rectangle.RenderTransform>
                    <Rectangle.OpacityMask>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Offset="0" Color="#FF000000"/>
                            <GradientStop Offset="0.3" Color="#FF000000"/>
                            <GradientStop Offset="0.6" Color="#00000000"/>
                            <GradientStop Offset="0.6001" Color="#FF000000"/>
                            <GradientStop Offset="1.0" Color="#FF000000"/>
                        </LinearGradientBrush>
                    </Rectangle.OpacityMask>
                    <Interactivity:Interaction.Behaviors>
                        <Behaviors:MatrixMotionBehavior Height="600"/>
                    </Interactivity:Interaction.Behaviors>
                </Rectangle>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

One thing that may jump out is a few behaviors. We'll look at these in a second. Essentially, the binding will create our matrix of columns and rows of characters. The key to the effect is the rectangle in each column. You'll notice it has an opacity mask and a negative margin. This allows me to mask the intensity of green on the characters because the rectangle overlays them. The negative margin starts the rectangle over the top of the page so I can bring it down to cover the characters. In order to have different characters "streaming" at different speeds, I simply offset the vertical position of the rectangle using a storyboard run at different speeds. Here is the behavior:

public class MatrixMotionBehavior : Behavior<FrameworkElement>
{
    private static readonly Random _random = new Random();

    public int Height { get; set; }

    protected override void OnAttached()
    {
        var storyboard = new Storyboard();
        var sbName = HelperExtensions.UniqueName();
        storyboard.SetValue(FrameworkElement.NameProperty, sbName);

        var da = new DoubleAnimation
                        {
                            Duration = TimeSpan.FromSeconds(1.0 + _random.NextDouble()*8.0)
                        };

        da.SetValue(FrameworkElement.NameProperty, HelperExtensions.UniqueName());

        var translateTransform = AssociatedObject.WithTransform<TranslateTransform>();
        Storyboard.SetTarget(da, translateTransform);
        Storyboard.SetTargetProperty(da, new PropertyPath("(TranslateTransform.Y)"));

        da.RepeatBehavior = RepeatBehavior.Forever;
        da.From = -1*Height;
        da.To = Height*2;

        storyboard.Children.Add(da);
        AssociatedObject.Resources.Add(sbName, storyboard);
        storyboard.Begin();
    }
}

The behavior takes whatever it is attached to and creates a storyboard that moves the Y offset using a translate transform. It will animate through whatever range is specified by the height. I knew I'd tweak this in XAML so I didn't make it a dependency property, but it could be for binding. I have to give the storyboards a unique name and add them to the resources of the container before I can launch them.

To grab the translate transform, I use a helper method I created that always ensures I have a valid transformation to work with. It is non-destructive, so if there are other transformations, it will work nicely with them. For example, if there is a scale transform, this helper extension with create a transformation group, move the scale transform into the group, then add the translation transform. You can close this generic extension with any transformation:

public static T WithTransform<T>(this UIElement control) where T: Transform, new() 
{
    T transform;

    if (control.RenderTransform == null)
    {
        transform = new T();
        control.RenderTransform = transform;
    }
    else if (control.RenderTransform is TranslateTransform)
    {
        transform = (T) control.RenderTransform;
    }
    else if (control.RenderTransform is TransformGroup)
    {
        var g = (TransformGroup) control.RenderTransform;
        transform = (from t in g.Children where t is T select (T)t).FirstOrDefault();
        if (transform == null)
        {
            transform = new T();
            g.Children.Add(transform);
        }
    }
    else
    {
        var g = new TransformGroup();
        var temp = control.RenderTransform;
        control.RenderTransform = g;
        g.Children.Add(temp);
        transform = new T();
        g.Children.Add(transform);
    }

    return transform;
}

I also have an extension to ensure unique names:

public static string SetUniqueName(this UIElement control)
{
    var guid = UniqueName();
    control.SetValue(FrameworkElement.TagProperty, guid);
    return guid;
}

public static string UniqueName()
{
    return Guid.NewGuid().ToString().Replace("-", string.Empty);            
}

At this point we have a fairly serviceable effect, with two problems. First, the performance is less than par because the render engine has to manage every individual TextBlock on the page. The second issue is that without clipping, the rectangle ends up masking other areas of the page that wouldn't be affected. To fix the clip, I used a behavior that automatically creates a clip the size of the container it is bound to:

public class Clip
{
    public static bool GetToBounds(DependencyObject depObj)
    {
        return (bool)depObj.GetValue(ToBoundsProperty);
    }

    public static void SetToBounds(DependencyObject depObj, bool clipToBounds)
    {
        depObj.SetValue(ToBoundsProperty, clipToBounds);
    }

    public static readonly DependencyProperty ToBoundsProperty =
    DependencyProperty.RegisterAttached("ToBounds", typeof(bool),
    typeof(Clip), new PropertyMetadata(false, OnToBoundsPropertyChanged));

    private static void OnToBoundsPropertyChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
    {
        var fe = d as FrameworkElement;
        if (fe != null)
        {
            ClipToBounds(fe);
            fe.Loaded += FeLoaded;
            fe.SizeChanged += FeSizeChanged;
        }
    }

    private static void ClipToBounds(FrameworkElement fe)
    {
        if (GetToBounds(fe))
        {
            fe.Clip = new RectangleGeometry
                            {
                Rect = new Rect(0, 0, fe.ActualWidth, fe.ActualHeight)
            };
        }
        else
        {
            fe.Clip = null;
        }
    }

    static void FeSizeChanged(object sender, SizeChangedEventArgs e)
    {
        ClipToBounds(sender as FrameworkElement);
    }

    static void FeLoaded(object sender, RoutedEventArgs e)
    {
        ClipToBounds(sender as FrameworkElement);
    }
}

Attaching this creates a clip the size of the containing grid, so when the rectangles are off the top of the screen, they don't overlay the header of the page.

Next, to keep from having to re-render every character, I decided to capture each column as an image. The columns remain static and it is only the mask that moves (I could probably have extended this to make a single image of the entire frame as well). This considerably improved performance although it is still takes significant CPU to recalculate the masks each frame. The freeze behavior can attach to any UIElement inside a grid. It will automatically render the element to an image, then swap the element with the snapshot of the element:

public class FreezeBehavior : Behavior<FrameworkElement>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        var parent = VisualTreeHelper.GetParent(AssociatedObject) as Panel;

        if (parent == null)
        {
            return;
        }

        var bitmap = new WriteableBitmap(AssociatedObject, new TranslateTransform());
        bitmap.Invalidate();

        var image = new Image {Width = bitmap.PixelWidth, Height = bitmap.PixelHeight, Source = bitmap};
        image.SetUniqueName();

        var pos = parent.Children.IndexOf(AssociatedObject);
        parent.Children.Remove(AssociatedObject);
        parent.Children.Insert(pos, image);            
            
        return;
    }        
}

While there may be some other ways to tweak this, I was very satisfied with the end result. By taking the challenge and breaking it into small, specific steps I was able to create the effect fairly closely to how I intended and then overlay the blog entries on top of it.

In the next post for this series, I'll tackle the more practical task of creating a custom panel to use in a list box for a carousel-like effect.

The source for this project is available from my home page: JeremyLikness.com.

Jeremy Likness

I knocked out quite a few items for the next release of Jounce, the primary being explicit support for multiple views bound to the same view model. In the previous version, the visual state binding would only reflect the most recent view (and a bug prevented the actual binding of the view model, but that's been fixed).

The changes are targeted for release 1.0, but you can download the latest now simply by navigating to the Source Code tab and then clicking "download" in the upper right under "Latest Version."

That same download addresses several items I received requests for.

Refactoring the Simple Navigation to use Regions

While I've provided examples of navigation with regions and without, the region version was very different than the simple navigation example that was without regions. Someone suggested that I build an example to show the same solution, but using regions. I decided to do that and a little more ... but first, let's focus on how I refactored the SimpleNavigation example to demonstrate SimpleNavigationWithRegion.

First, I was able to take out the bindings and code that were explicitly placing the controls because the region management takes it over. If you recall, creating a region is as simple as tagging it:

   <ContentControl Grid.Row="0" Regions:ExportAsRegion.RegionName="NavigationRegion"/>
        <ItemsControl Grid.Row="1" Regions:ExportAsRegion.RegionName="ShapeRegion">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>

Notice what I did for the shape region: I used an items control instead of a content control, but overrode the panel to be a Grid. This will force the views routed to the region to take up the same space, but there is a method to my madness ... I'll explain in a bit.

In the views, we place a simple tag to route the region:

[ExportViewToRegion("RedSquare", "ShapeRegion")]
public partial class RedSquare ...

The ShellViewModel no longer has to manage the navigation region or maintain state. In fact, the only thing it needs to do is raise a navigation event for the navigation region so the navigation controls will show. Here is what it ends up looking like:

[ExportAsViewModel("Shell")]
public class ShellViewModel : BaseViewModel, IPartImportsSatisfiedNotification
{       
    public void OnImportsSatisfied()
    {           
        EventAggregator.Publish(new ViewNavigationArgs("Navigation"));
    }               
}

The old navigation view used a command to fire navigation. The latest Jounce features a NavigationTrigger that you can use to trigger navigation from XAML. In this case, we bind it the view name that we build from the meta data for the views:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Button Margin="5" Content="{Binding Item2}" ToolTipService.ToolTip="{Binding Item3}">
            <Interactivity:Interaction.Triggers>
                <Interactivity:EventTrigger EventName="Click">
                    <Services:NavigationTrigger Target="{Binding Item1,FallbackValue=Navigation}"/>
                </Interactivity:EventTrigger>
            </Interactivity:Interaction.Triggers>
        </Button>
    </DataTemplate>
</ItemsControl.ItemTemplate>

The "item1" etc comes from the tuple I create by parsing meta data to get the button names and tool tips. The behavior now handles firing the navigation event for me, and because the views are wired to the region, the region manager will place them on the control surface.

Multiple Views per ViewModel

The original Jounce supported binding multiple view models to a view, but a bug prevented the second instance from being bound. Not only is this fixed, but I also improved the support for the visual state manager. We'll cover that in a second. First, I wanted to make a view model called ShapeViewModel to handle some transitions. The same view model will be bound to all of the shape controls. To do this, I simply created a simple Binding class and exported all of the bindings:

public class Bindings
{
    [Export]
    public ViewModelRoute Circle
    {
        get { return ViewModelRoute.Create("ShapeViewModel", "GreenCircle"); }
    }

    [Export]
    public ViewModelRoute Square
    {
        get { return ViewModelRoute.Create("ShapeViewModel", "RedSquare"); }
    }

    [Export]
    public ViewModelRoute Text
    {
        get { return ViewModelRoute.Create("ShapeViewModel", "TextView"); }
    }
}

Jounce handles this with no problem and simply uses the same view model (still only calling Initialize the first time it is created) and binds it to each view (calling Activate whenever a view is navigated to, and passing in the view name).

So what can we do with this?

Page Transitions

Another question I received was, "How do I do transitions between pages, i.e. fade one out, the next in, etc?" Obviously with a content control this is impossible because the new view replaces the old view.

But there is a solution!

Instead of replacing views, you can take the approach I did in the sample application, and use an items control with a grid for a panel. This allows you to stack the views on the same surface, but manipulate their visibility using visual states.

For visual states, I used the same set of groups and transitions on every control. There is a visible and a hidden state. The hidden state slowly expands and fades the old control.

<VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ShowAndHide">
                <VisualStateGroup.States>
                    <VisualState x:Name="ShowState">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="LayoutRoot"
                                                       Storyboard.TargetProperty="(UIElement.Visibility)">
                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Visibility>Visible</Visibility>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                            <DoubleAnimation 
                                             Duration="0:0:0"
                                             Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                                             From="0.3" To="1.0"/>
                            <DoubleAnimation Duration="0:0:0" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                                             From="0.3" To="1.0"/>
                            <DoubleAnimation Duration="0:0:0" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                             From="0.3" To="1.0"/>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="HideState">
                        <Storyboard>
                            <DoubleAnimation Duration="0:0:0" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                                             From="1.0" To="1.2"/>
                            <DoubleAnimation Duration="0:0:0" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                                            From="1.0" To="1.2"/>
                            <DoubleAnimation Duration="0:0:0" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                             From="1.0" To="0.3"/>
                            <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="LayoutRoot"
                                                       Storyboard.TargetProperty="(UIElement.Visibility)">
                                <DiscreteObjectKeyFrame KeyTime="0:0:0.0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Visibility>Collapsed</Visibility>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup.States>
                <VisualStateGroup.Transitions>                    
                    <VisualTransition To="HideState">
                        <Storyboard>
                            <DoubleAnimation 
                                Duration="0:0:0.2"
                                Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                                             From="1.0" To="1.2"/>
                            <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                                             From="1.0" To="1.2"/>
                            <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="(UIElement.Opacity)"
                                             From="1.0" To="0.3"/>
                            <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="LayoutRoot"
                                                       Storyboard.TargetProperty="(UIElement.Visibility)">
                                <DiscreteObjectKeyFrame KeyTime="0:0:0.2">
                                    <DiscreteObjectKeyFrame.Value>
                                        <Visibility>Collapsed</Visibility>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualTransition>
                </VisualStateGroup.Transitions>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

I placed this in each control. So what now? Because Jounce supports multiple views for the view model, and because Jounce passes in the view information, the view model can trigger state changes without knowing what the views are or even how to interact with the visual state manager - it only needs to know the name of the state.

Take a look at the ShapeViewModel:

[ExportAsViewModel("ShapeViewModel")]
public class ShapeViewModel : BaseViewModel
{
    private string _lastView = string.Empty;

    public override void _Activate(string viewName)
    {
        if (string.IsNullOrEmpty(_lastView))
        {
            _lastView = viewName;
        }
        else if (!_lastView.Equals(viewName))
        {
            EventAggregator.Publish(new ViewNavigationArgs(_lastView) {Deactivate = true});
            _lastView = viewName;
        }

        GoToVisualStateForView(viewName, "ShowState", true);
    }

    public override void _Deactivate(string viewName)
    {
        GoToVisualStateForView(viewName, "HideState", true);
    }
}

Basically, it simply remembers the last view name. When an activation occurs, it raises the deactivate event for the old view. The activation then sets the visual state to the ShowState for the view being activated. On the deactivation call, it sets the visual state to the HideState for the view being deactivated. The net result is that as you navigate, the old views seem to pop and disappear as the new views appear.

Also note that Jounce automatically wires the visual state transitions to execute on the UI thread for you.

Jeremy Likness

One common request I get is how Jounce can work with the Navigation Framework.

My first reply is always, "Why do you want to use that?" As you can see in previous posts, the Jounce navigation works perfectly fine with region management to manage your needs. If you want the user to be able to "deep link" to a page, you can easily process the query string and parse it into the InitParams for the application and deal with them there.

For the sake of illustration, however, I wanted to show one way Jounce can work with an existing navigation framework. In fact, to make it easy to follow along, the quick start example works mainly from the "Navigaton Application" template provided with Silverlight.

As a quick side note, I am very much aware of the INavigationContentLoader interface. This may be the way to go and in the future I might write an adapter for Jounce, but I just don't see a compelling need to have URL-friendly links as I typically write applications that act like applications in Silverlight, not ones that try to mimic the web by having URLs.

The example here is available with the latest Jounce Source code (it's not part of an official release as of this writing so you can download it using the "Latest Version - Download" link in the upper right).

To start with, I simply created a new Silverlight navigation application.

Without overriding the default behavior, the navigation framework creates a new instance of the views you navigate to. To get around this model which I believe is wasteful and has undesired side effects, I changed the mapping for the various views to pass to one control that manages the navigation for me:

<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/Views/JounceNavigation.xaml"/>
    <uriMapper:UriMapping Uri="/ShowText/{text}" MappedUri="/Views/JounceNavigation.xaml?view=TextView&text={text}"/>
    <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/JounceNavigation.xaml?view={pageName}"/>                        
</uriMapper:UriMapper>

Notice how I can translate the path to a view parameter, and that I am also introducing a mapping for "ShowText" that we'll use to show how you can grab parameters.

The JounceNavigation control will get a new copy every time, but by using MEF it will guarantee we always access the same container. To do this, I created NavigationContainer and it contains a single content control with a region so the region is only exported once:

<ContentControl 
                    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                    HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
                    Regions:ExportAsRegion.RegionName="MainContainer"/>

In the code-behind, I simply export it:

namespace SilverlightNavigation.Views
{
    [Export]
    public partial class NavigationContainer
    {
        public NavigationContainer()
        {
            InitializeComponent();
        }
    }
}

Now we can use this single container in the JounceNavigation control. What we want to do is attach it when we navigate to the control, and detach it when we navigate away (a control can only have one parent, so if we don't detach it, we'll get an error when the next view is created if the previous view hasn't been garbage-collected yet).

The navigation control also does a few more things to integrate with the navigation framework. It will remember the last view so it can deactivate the view when navigating away. It will default to the "Home" view but basically takes any view passed in (based on the uri mappings we defined earlier) and raises the Jounce navigation event. Provided the view targets the region in our static container, it will appear there. Normally I'd do all of this in a view model but wanted to show it in code-behind for the sake of brevity (and to show how Jounce plays nice with standard controls as well).

public partial class JounceNavigation
{
    [Import]
    public IEventAggregator EventAggregator { get; set; }

    [Import]
    public NavigationContainer NavContainer { get; set; }

    private static string _lastView = string.Empty;
                
    public JounceNavigation()
    {
        InitializeComponent();
        CompositionInitializer.SatisfyImports(this);
        LayoutRoot.Children.Add(NavContainer);
        if (!string.IsNullOrEmpty(_lastView)) return;
        EventAggregator.Publish("Home".AsViewNavigationArgs());
        _lastView = "Home";
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (NavigationContext.QueryString.ContainsKey("view"))
        {
            var newView = NavigationContext.QueryString["view"];
            _lastView = newView;
            EventAggregator.Publish(_lastView.AsViewNavigationArgs()); 
            EventAggregator.Publish(NavigationContext);
        }
    }

    protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
    {
        if (!string.IsNullOrEmpty(_lastView))
        {
            EventAggregator.Publish(new ViewNavigationArgs(_lastView) {Deactivate = true});
        }
        LayoutRoot.Children.Remove(NavContainer);
    }

}

Notice that we publish two events. The first is the view navigation to wire in the target view. The second is a NavigationContext event. The navigation context contains all of the query string information. Any view that needs to pull values from the query string can simply listen for this event. Because the view navigation is called first, the view will be in focus and ready when it receives the context message to parse any parameters.

To demonstrate this, let's look at the TextView control. When you pass text in the url, it will simply display it. The XAML looks like this:

<Grid x:Name="LayoutRoot" Background="White">
    <TextBlock x:Name="TextArea"/>
</Grid>

The code-behind looks like this:

[ExportAsView("TextView")]
[ExportViewToRegion("TextView", "MainContainer")]
public partial class TextView : IEventSink<NavigationContext>, IPartImportsSatisfiedNotification
{
    [Import]
    public IEventAggregator EventAggregator { get; set; }

    public TextView()
    {
        InitializeComponent();                        
    }

    public void HandleEvent(NavigationContext publishedEvent)
    {
        if (publishedEvent.QueryString.ContainsKey("text"))
        {
            TextArea.Text = publishedEvent.QueryString["text"];
        }
    }

    public void OnImportsSatisfied()
    {
        EventAggregator.SubscribeOnDispatcher(this);
    }
}

Pretty simple - it exports as a view name, targets the main container region, and then registers as the event sink for NavigationContext messages. In this case we only have one listener. In more complex scenarios with multiple view models listening, the view model would simply inspect the "view" parameter to make sure it matches the target view (it could easily find this in a generic way by asking the view model router) and ignore the message if it does not.

To convert the "Home" and the "About" page took only two steps.

First, I changed them from Page controls to UserControl controls. I simply had to change the tag in XAML and remove the base class tag in the code-behind and the conversion was complete. Second, I tagged them as views and exported them to the main region:

namespace SilverlightNavigation.Views
{
    [ExportAsView("About")]
    [ExportViewToRegion("About", "MainContainer")]
    public partial class About 
    {
        public About()
        {
            InitializeComponent();
        }       
    }
}

That's it - now I have a fully functional Jounce application that uses the navigation framework and handles URL parameters. You can click on the "text" tab to see the sample text and then change the URL to confirm it parses the additional text you create.

Jeremy Likness

Now that we've explored the concept of Jounce navigation, the next logical step is to examine region management. This concept was introduced by the Prism framework and is very powerful and functional for both WPF and Silverlight applications.

Region management deals with a few moving pieces. A region is simply an area of the display that has been marked or tagged to hold a control. Regions are as flexible as their containers: they can be a fixed size or dynamic. They can hold a single control or a collection of controls. Typical containers include ContentControl for single controls, ItemsControl for multiple controls, and any type of panel including Grid and TabControl.

Regions are tagged with a region name. In Jounce, tagging a region is as simple as using the ExportAsRegion attached property, as you can see here:

<Controls:TabControl Grid.Row="1" Regions:ExportAsRegion.RegionName="TabRegion"/>
<ItemsControl Grid.Row="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
                Regions:ExportAsRegion.RegionName="AppRegion">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

Once a region is tagged, a view or control can be pointed at the region. In Jounce, you would use the ExportViewToRegion tag and pass the view's tag and the target region. In this example, the view is exported as we discussed in the previous post. An additional tag is added to route the view to the target region:

[ExportAsView(REQUEST_SQUARE, MenuName = "Request a Square")]
[ExportViewToRegion(REQUEST_SQUARE,LocalRegions.TAB_REGION)]
public partial class RequestSquare
{
}

So how does the view end up in the region? This is where the region adapter comes into play. The region adapter knows how to manage views in a specific region. For example, in Jounce, the ContentRegion adapter manages content controls, while the ItemsRegion adapter manages items controls. Because you can wrap these in a panel type, or override the ItemsControl to use any panel from Canvas to Grid or StackPanel as the container, these are the only adapters that ship with Jounce. We'll talk about creating your own adapters in a little while.

Here is the example from the Jounce quick start, showing the two regions and some controls:

Jounce region management

First, let's see how the view ends up in the region. The region is tagged and the RegionManager is notified. This manager knows about all regions and all region adapters. The region manager imports all of the view metadata for region routes:

[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportViewToRegionMetadata>[] Views { get; set; }

It also exposes an indexer making it easy to find the region metadata given a view tag:

public IExportViewToRegionMetadata this[string viewType]
{
    get
    {
        return (from v in Views
                where v.Metadata.ViewTypeForRegion.Equals(viewType, StringComparison.InvariantCultureIgnoreCase)
                select v.Metadata).FirstOrDefault();
    }
}

When we navigate to the view, you'll remember the core Jounce framework wires the view to the view model, then raises the ViewNavigatedArgs message. This is what region management listens for:

[Export(typeof (IRegionManager))]
public class RegionManager : IRegionManager, IPartImportsSatisfiedNotification, IEventSink<ViewNavigatedArgs>
{
   ...
   public void HandleEvent(ViewNavigatedArgs navigationEvent)
    {
        if (navigationEvent.Deactivate)
        {
            DeactivateView(navigationEvent.ViewType);
        }
        else
        {
            ActivateView(navigationEvent.ViewType);
        }
    }
}

The activate and deactivate are similar. If this is the first time the region manager has seen the view, it stores the tag for the view, then finds the region adapter that manages the type of the view. It then informs the region adapter of the view so that it can be added to the region adapter's internal collection. Finally, regardless of whether the view has been "seen" before or not, all adapters that manage the view are called upon to activate the control.

var viewInfo = GetViewInfo(viewName);

if (viewInfo == null)
{
    return;
}

if (!_processedViews.Contains(viewName) && _regions.ContainsKey(viewInfo.Metadata.TargetRegion))
{
    // add any views that were waiting for this region to become available 
    var region = _regions[viewInfo.Metadata.TargetRegion];
    var regionAdapterInfo = GetRegionAdapterForType(region.GetType());
    if (regionAdapterInfo != null)
    {
        var regionAdapter = regionAdapterInfo.Value;
        regionAdapter.AddView(viewInfo.Value, viewName, viewInfo.Metadata.TargetRegion);
        _processedViews.Add(viewName);
    }
                
}
            
foreach(var ra in GetRegionAdaptersForView(viewName))
{
    ra.ActivateControl(viewName, viewInfo.Metadata.TargetRegion);                
}             

For the built in content control, activation is simple: the content is updated ot the new control, overwriting the old one (it still remains in memory, but is not longer part of the content control as a view).

public override void ActivateControl(string viewName, string targetRegion)
{
    _ValidateControlName(viewName);
    _ValidateRegionName(targetRegion);

    var region = Regions[targetRegion];            
    region.Content = Controls[viewName];           
}      

First, it validates it has the view. Next, it validates it has the region. Finally, it grabs the region (which in this case is a content control) and sets the content to the control.

So how does the region manage the view? The RegionAdapterBase is typed to the region (i.e. ContentControl) and keeps track of regions (a dictionary with region names and the actual content controls) and views (a dictionary with the view tag and the actual view control). It has default behaviors for activating and deactivating a control, and then allows the adapter to override this. The adapter simply exports itself with the type of region it can handle:

[RegionAdapterFor(typeof(ContentControl))]
public class ContentRegion : RegionAdapterBase<ContentControl>
{
}

Note that it inherits from the base control, typed to the type it is handling, and also exports the type so the region manager can find it.

Because tab controls have headers, Jounce doesn't natively provide an adapter because you might want the header to behave differently than Jounce would expect. In the quickstart, an example tab adapter is provided. Here is the code:

[RegionAdapterFor(typeof(TabControl))]
public class TabRegion : RegionAdapterBase<TabControl>
{
    [Import]
    public IEventAggregator EventAggregator { get; set; }

    private readonly List<string> _addedViews = new List<string>();

    [ImportMany(AllowRecomposition=true)]
    public Lazy<UserControl, IExportAsViewMetadata>[] Views { get; set; }               
        
    public override void ActivateControl(string viewName, string targetRegion)
    {
        _ValidateControlName(viewName);
        _ValidateRegionName(targetRegion);

        var region = Regions[targetRegion];

        if (!_addedViews.Contains(viewName))
        {
            _addedViews.Add(viewName);
            _SetupTabForView(region, viewName);
        }
                                   
        region.SelectedIndex = _addedViews.IndexOf(viewName);
    }

    private void _SetupTabForView(ItemsControl region, string viewName)
    {
        var metadata =
            (from v in Views where v.Metadata.ExportedViewType.Equals(viewName) select v.Metadata).FirstOrDefault();

        var header = metadata == null ? viewName : metadata.MenuName;
            
        var tabControlItem = new TabItem {Header = header, Content = Controls[viewName]};            

        region.Items.Add(tabControlItem);           
    }
}

In this case, the tab adapter keeps track of views added as well. It imports the metadata for the views because we'll use the extra fields such as "menu name" to build out our tabs. When the view is activated for the first time, the meta data is inspected and a TabItem is created with the menu name as the header and the control as the body. It is added to the tab control. Anytime the navigation event for the view is fired, the tab adapter sets the index to the correct tab so it is selected. This allows other triggers to navigate to the correct tab.

As you can see, region management greatly simplifies the problem of navigation by allowing easy, composite sections that can be nested as deep as necessary. Classes don't have to understand the layout or regions at all: there is no need to understand how to select a tab, because the region manager handles this. All that happens is the navigation event is raised, then the region manager steps in and takes care of the rest.

Here's a quick tip as well: you might want to have some fancy transitions that appear when you move from one page to the next. The content region prevents this because the old control is immediately overwritten. How would you handle this in Jounce?

It's easy. Use an ItemsControl instead and for each control, provide a visual state for showing the control and hiding it. That visual state can have any type of animation you like. Override the template panel for the control to be a Grid so all of the views are stacked on top of each other.

In the _Activate method of the view model, simply go to the visual state for the "show" state. In the _Deactivate, go to the visual state for the "hide" state. You can set up a class that listens for navigation events and keeps track of the last item. Whenever a new item is navigated, it will publish the "deactivate" event for the old item. This allows the old item to transition away while the new item transitions in. While the views are stacked in a region that handles multiple views, only the view with the "show" visual state will be visible at any given time.

Next post I'll share how you can integrate Jounce navigation with the built-in Silverlight navigation framework.

Jeremy Likness

More Posts Next page »