A few weeks ago, after presenting at CodeMastery, I sat down with Carl Franklin from dnrTV! to discuss WPF with MVVM.  The discussion is centered around the demo portion of my presentation entitled WPF with MVVM: From the Trenches.  This presentation is the precursor to the work I have done with MVVM Fabric.  Without further ado, check it out here: http://dnrtv.com/default.aspx?ShowID=184 – complete with an un-flattering pic Winking smile

Share

Using TriggerAction

0

A few days ago, I wrote about using MVVM Fabric’s ActionCommand.  Commanding can be useful with controls that provide a Command property, such as Buttons and MenuItems.  However, commanding doesn’t help when you want to wire up arbitrary events to your view model.  That is where TriggerAction come in.

Overview

TriggerAction is a look-less framework element that wires itself up to whatever event you specify on whatever control you specify.  When that event is raised, TriggerAction calls whatever method you specify on your view model.

TriggerAction was written by Rocky Lhotka for his business object framework, CSLA .NET.  Since CSLA is open source, Rocky gave me permission to include TriggerAction with MVVM Fabric because of the great value it would provide consumers of the library.  I have been using a precursor of TriggerAction, called InvokeMethod, on my projects with great success.  While InvokeMethod has some limitations (no designer support and the ability to only wire one event for a control), TriggerAction provides a more robust implementation and eliminates these issues.

Wiring an event to a method

There’s really two different ways that I typically use TriggerAction.  The first way is when I really only care if an event happened.

For this example, we will wire up TriggerAction to call the Close method on our view model when a button is clicked.  We first need to name the button that we will be hooking events from.

<Button
    Name="CloseButton"
    Content="Close" />

Next we place the TriggerAction on our view.

<mvvm:TriggerAction
    TargetControl="{Binding ElementName=CloseButton}"
    MethodName="Close"
    TriggerEvent="Click"
    Width="0"
    Height="0" />

Notice that I used an Element Binding for the TargetControl property.  That is how we tell TriggerAction to listen for the click event on our button.  I also set the MethodName property with the name of the method we want called.  It is important to note that TriggerAction looks for the method specified on its DataContext.  So, you have to make sure that the DataContext is your view model if you want it to call methods on your view model.

Now we need to write the Close method on our view model.

public void Close()
{
    // Do Stuff.
}

We’re all set.  When the Click event is raised on our button, TriggerAction will look for a method called Close on its DataContext (which is our view model).  The method it looks for must have 0 or 2 arguments.  We have the 0 argument version here because we only care that the event happened.

Wiring an event to a method with a MethodParameter

The second way I typically use TriggerAction is for those situations where I need to pass a parameter to my method when the event I care about is raised.

For this example (and the one you will see in the sample application), we will wire up the MouseDoubleClick event on a ListView to pass the SelectedItem back to our method on the view model.

First, the ListView.

<ListView
    Name="MoviesList"
    ItemsSource="{Binding Movies}" />

 

Next, the TriggerAction.

<mvvm:TriggerAction
    TargetControl="{Binding ElementName=MoviesList}"
    MethodName="MovieSelected"
    MethodParameter="{Binding Path=SelectedItem, ElementName=MoviesList}"
    TriggerEvent="MouseDoubleClick"
    RebindParameterDynamically="True"
    Width="0"
    Height="0" />

 

There are two things different about our usage of TriggerAction here.  The first difference is the addition of the MethodParameter property, which we are binding to the SelectedItem property on the MoviesList element.  The second is setting RebindParameterDynamically to true.

The MethodParameter property on TriggerAction is where you bind whatever you want from the view to be passed back your view model.  This can be something on the element you are listening for events on or something somewhere else on the view.

The RebindParameterDynamically property is really cool.  When this is set to true, TriggerAction will go out and rebind to the method parameter before calling back to your method so that you are always sending back the latest and greatest.  Since not all of the properties you want to bind to raise property changed events, this is a huge benefit.

Now, on to the view model.  As I mentioned before, when looking for methods on our view model, TriggerAction will look for methods with either 0 or 2 parameters.  Since we need that MethodParameter passed in, we will need the 2 parameter version.

public void MovieSelected(object sender, ExecuteEventArgs args)
{
    var movie = args.MethodParameter as Movie;
    // Do Stuff.
}

 

This is a typical event handler method signature.  The event args that are passed through are ExecuteEventArgs, which have some useful properties.  The property we care about right now is the MethodParameter property, which needs to be cast before we use it because it is of type Object.  Once we cast it as our Movie business object, the view model is free to do what it needs with it.

Conclusion

Although commanding is a decent start to executing methods on your view model, TriggerAction is a much more robust solution.  With drag-and-drop designer support, the ability to bind a method parameter and the ability to have that method parameter dynamically updated at execution time, TriggerAction is an extremely powerful way to wire arbitrary events from your view to your view model.

Share

One of the biggest problems I encountered while writing WPF apps with MVVM is navigation.  The traditional approach to navigation would be to have one view create the view being navigated to.  Now, there’s a couple of issues with that approach which make it less than desirable.  The first issue is that having one view create another view heavily couples the two views.  The second issue is that this approach quickly becomes very difficult (if not impossible) to unit test.

Things get more complicated when view models are introduced.  Since the functionality that initiates the navigation is going to be in the view model, that would mean the view model would have to know about the new view.  When I structure an MVVM solution for WPF, I create a separate class library for the view models.  The client project (which contains the views) needs to have a reference to the view models project in order to use them.  That means there would be a circular dependency if the view model project had a reference to the view project as well.  Doing the traditional approach with this project structure is no longer even an option.

MVVM Fabric solves the navigation problem with some convention, some configuration, a pinch of dependency injection and a dash of the message bus.

10,000 ft View

MVVM Fabric funnels all navigation through one source, the ViewController.  The ViewController subscribes to the message bus to listen for ShowViewMessages requesting views.  When a view request comes through, the ViewController coordinates the resolution and creation of the view and its view model.  Then the ViewController takes the new view and passes it along to the view placer to be placed in the application.

By leaning on the message bus to request a view, writing unit tests for the view model making the request becomes a breeze.  By letting all navigation flow through the ViewController, it de-clutters your codebase by eliminating the need for code creating views throughout the application.  This decoupling will greatly simplify your application and each view model can focus on its own responsibilities and not have to worry about the specifics of any other view or view model.

Convention

As I mentioned, there is an element of convention required to leverage the navigation model provided by MVVM Fabric.  The conventions are as follows:

  • All view models must have a default constructor.
  • View models have the option of providing a Load method as a way of allowing itself to be loaded during the dynamic creation process provided by MVVM Fabric.  The Load method may take 0 or 1 arguments.
    • If there is an argument, it can be whatever is required by the view model to load itself.
    • If more than one thing is required to load the view model, I recommend creating some sort of criteria class that contains any required data.
  • A class inheriting from ViewTargets must be provided with unique definitions for all navigable views in the application.

The reason that all view models must have a default constructor is that they are dynamically instantiated when a view is loaded.  Since there are many scenarios where a view model will need some information to load itself (picture a detail view, for example), MVVM Fabric looks for a public Load method on the view model and calls it if found.  That Load method may be a no argument method which simply kick-starts the loading needed for the view model or it may take a single parameter.  If the Load method takes a parameter, a parameter must be provided when the view is requested.  That’s where the ShowViewMessage comes into play.

The ShowViewMessage has a ViewTargets parameter (which tells the ViewController which view is being requested) and an optional parameter called LoadArgs.  LoadArgs can be anything required by the view model, but if something is provided a Load method which takes that object type as a parameter must exist on the view model or an exception will be thrown.

If you saw my presentation WPF with MVVM: From the Trenches, you heard me talking about how ViewTargets is an enumeration.  While refactoring my navigation code into a stand-alone library for MVVM Fabric, one of the issues I had to overcome is the fact that enumerations cannot be inherited from and extended from an external object.  The reason I liked using an enumeration to articulate all the navigable views in the first place is because it provided a level of safety at compile time when views are requested.  I could have used strings instead to identify views, but that would not make refactoring easy.  To overcome this limitation of enums, I leveraged a concept introduced by Hugh Ang to create an Enumeration class which acts like an enum, but can be extended.  It’s not a perfect solution, but it does help address the compile-time and refactoring issues.  The new ViewTargets inherits from this Enumeration class and must be further inherited from in your implementation.

Configuration

In order to leverage the navigation model provided by MVVM Fabric, you must provide implementations to an interface or two: IViewPlacer and optionally IViewAuthorizer.

IViewPlacer is what will actually place the views when the navigation model has loaded the view and it’s view model.  I leave that implementation up to you because each application is different in how views are presented.  The sample application provides an implementation that works with the tabbed interface used by Movies.  MVVM Fabric does contain an implementation of IViewPlacer for views displayed as modal dialogs because this will likely be the same across applications.  The sample application shows the usage of ModalViewPlacer in conjunction with it’s custom IViewPlacer to illustrate how you could implement a combination of the two.

IViewAuthorizer is an interface which can optionally be implemented to give you control over whether the user is authorized to see each view before it is shown.  This allows you to put restrictions on your views from one location.

Enough talk, time for code!

Here’s the part you are probably waiting for, how do I make it work?  Here are the steps that you need to take to get up and running.

1.  Inherit from ViewTargets and provide values for your views.

public class MoviesViewTargets : ViewTargets
{
    public static ViewTargets Detail = 2;
    public static ViewTargets AdvancedSearch = 3;
}

2.   Provide an implementation for IViewPlacer (unless you strictly use ModalViewPlacer)

public sealed class ViewPlacer : IViewPlacer
{
    private TabControl MainTabControl { get; set; }
    private IMessageBus MessageBus { get; set; }

    public ViewPlacer(Window appWindow, TabControl mainTabControl)
    {
        MainTabControl = mainTabControl;
    }

    public void PlaceView(ViewResult viewResult)
    {
        // Place new view into MainTabControl
    }
}

Note: Your custom ViewPlacer would also be a good place to subscribe to CloseViewMessages from the message bus.  Since views have the ability to request that they be closed, it only makes sense to keep the showing and closing functionality in the same place.  You can see this in action with the sample application.

3.  Provide a way to wire up the IViewConfigurationResolver when the application starts up.

public sealed class ContainerConfiguration
{
    public static void InitContainer()
    {
        var viewConfigResolver = new ViewConfigurationResolver();
        InitNavigation(viewConfigResolver);
    }

    private static void InitNavigation(IViewConfigurationResolver viewConfigResolver)
    {
        viewConfigResolver.RegisterViewConfiguration<Detail>(MoviesViewTargets.Detail);
        viewConfigResolver.RegisterViewConfiguration<AdvancedSearch>(MoviesViewTargets.AdvancedSearch);
    }
}

Note: The sample application calls ContainerConfiguration.InitContainer() in the application’s OnStartup method.  I also do some configuration for Windsor Container in this method.

4 (Optional).  Provide an implementation for IViewAuthorizer.  This one is up to you since application security varies on a case-by-case basis.

5.  Instantiate the ViewController and all the pieces it needs.  This will probably be done in the code-behind of your main window.  The sample application uses Castle Windsor, so I will leave it up to you how you get all the pieces standing.

You’re There!

The steps described above may seem like a lot of work, but the work is almost all front-loaded.  When a new view is added, only steps 1 and 3 must be revised to accommodate the new view.

Now, let’s look at how to initiate navigation.

public void SelectMovie(Movie movie)
{
    var message = new ShowViewMessage(MoviesViewTargets.Detail, movie);
    MessageBus.Publish<ShowViewMessage>(message);
}

That’s it!  This example shows how to pass a parameter to the Detail view.  You could remove the LoadArgs parameter from the ShowViewMessage for those cases where there is either no need for a Load method on the view model or the Load method has no parameters.

From a testing perspective, the above example is extremely simple to write unit tests for.  You would simply assert that the message bus received a ShowViewMessage with the correct arguments.

Conclusion

The navigation model provided by MVVM Fabric takes a pain point with the MVVM pattern and smooths it over in a testable manner.  With all the navigation being handled in one place, it reduces the surface area that you must test for in your application.  A testable application is a maintainable application!

Share

Introducing MVVM Fabric

1

I’ve been working with MVVM on WPF applications for well over a year now on two major projects.  As the UI architect for both projects, I was the guy who had to figure out how to make things work in a way that was extensible and testable.  With each WPF project I did that leveraged MVVM, I found there were common problems that needed to be solved.  These common problems include communication between views, decoupled/testable navigation between views and commanding.  To solve these problems, I initially developed a solution and refactored as needed to fit the different scenarios I encountered.

After spending over a year with the solution, I feel that it stabilized well enough to be confident that I had the foundation for a more general purpose solution.   I have taken what I did on both projects and what I learned from them while doing it and created a library that I am calling MVVM Fabric.  The (mostly selfish) goal with MVVM Fabric was to create an MVVM library that I could weave into other projects with minimal effort.

The real trick was taking what I had integrated into my most recent project and extracting it in such a way that I could turn it into a library and keep it usable.

What is MVVM Fabric?

MVVM Fabric is the result of that exercise.  It is a WPF-centric library, written in C# 4.0, which helps address communication, navigation and commanding in an application leveraging MVVM.  It provides core functionality and leverages dependency injection to provide extensibility.

I have posted the library along with a sample application which uses it out on github: https://github.com/brentedwards/MvvmFabric.

If you have attended my presentation WPF with MVVM: From the Trenches or looked at the presentation materials, you will likely notice many similarities.  That presentation and the resulting sample application were both based on the same projects as MVVM Fabric.  So, I refactored that sample application to eat my own dog food and work out some kinks.  The result is something that I am happy with, though will likely be further extended as I (or you) see fit.

I plan to write several blog posts to provide a more in-depth introduction and explanation of the library (and reasons behind the decisions I made) in coming days.

Share