Tool windows with MVVM

I got the following great question today:

Robert…loved that July article on MVVM and AvalonDock.

You solved my adapting of “DocumentContent” MVVM views.

Now I need to do the same for “DockableContent” views. I am curious what general (or specific) guidelines you would recommend. In my case….there would be a fixed number of “DockableContent” views.

Setting the stage: A real-world example

To address this, let’s use the application I’m currently developing for my business to provide a concrete and real world example. My software is an easy to use financial planning tool that is based on a visual “lifeline” which is specific to the current user. Users can simply drag-and-drop financial items – called lifeline items – onto the lifeline, and the tool calculates the wide variety of financial metrics over time. For example, you can drag-and-drop expenses, employment, kids, mortgages, etc, and the tool will calculate income, expenses, assets, liabilities, etc.

To avoid (modal) dialog boxes – always a good usability practice to avoid dialog boxes! – I make heavy use of dockable tool windows. Furthermore, I enable and disable certain tool windows based on the type of document the user currently has open. In the screenshot below the user has a lifeline open and there are actually eight tool windows available! However by default only two of these are actually pinned open. In the image, the draggable lifeline items are displayed on the left, and the properties of the currently selected lifeline item are displayed on the right:

Other tool windows available are “Help” which is docked up to the top left, “Undo”, “Transactions” (which displays the financial transactions for the currently selected lifeline item), and “Lifeline item graph” (which displays a graph of the important financial aspects of the currently selected lifeline).

While the undo tool window is tied to the current document, almost all of the other tool windows available are tied to the currently selected item on the lifeline. When no lifeline item is selected, the properties window displays information about the lifeline as a whole. In the above screenshot the “baby” lifeline item is currently selected, and in the right-hand properties tool window you can see the initial baby expenses associated with that lifeline item including car seats, cribs, and monthly diaper expenses.

Of course I’m using MVVM for all of this!

 

Using MVVM to control available tool windows

As you can imagine I have a very rich domain logic layer, with hundreds of classes. This results in a very large view model layer as well (unless you are using dynamic proxies, or exposing your domain classes directly to the view). As mentioned in the MSDN article, I’m using a document manager adapter to keep the management of the documents in the view model layer and out of the view layer. I use a very similar separated approach to control which tool windows are open for each document type. This allows the view model layer to control which to Windows are available for a given document type (which is very powerful). However, I found that in the case of controlling tool windows, it was enough to simply have the view-model layer provide an IToolWindows interface with a collection of Boolean properties, where each Boolean property determines if a tool window is available or not. Then the view layer implements this interface with a concrete implementation that knows all about my docking component. The concrete implementation is then injected into the view model layer when the application is initializing. This is the standard “dependency injection” design pattern, however I typically do manual dependency injection to avoid the long-term maintenance ugliness of IOC containers.

This simplified approach avoids the need to raise many events (and therefore wire-up all the event listening code) but is different than the document-manager adapter approach discussed in the article. However for the sake of simplicity (around tool windows) and ease of implementation I was okay with this difference in my design.

The overall approach helps me follow my first bit of MVVM guidance:

MVVM Guideline #1: Strive to minimize the code used in the XAML code behind by putting as much code as possible in the view model layer (but don’t get stupid about it).

This approach has a small amount of code in view layer, which implements the interface and interacts with the docking controls. However, the vast majority of the code is in the view-model layer, which allows me to easily replace the docking controls if need be: I only have to replace the one class that implements the interface.

Of course, I get all the other benefits of MVVM such as separation-of-concerns, and the ability to easily write unit tests against the bulk of my code (in the view-model layer).

 

Using MVVM to display stuff related to the document

To display document related content in the tool windows, I have a special class called ActiveDocument in my view-model layer. Not surprisingly, this class always contains information about the currently active document, regardless of the type of document that is currently active. This class is actually a Singleton, and so it exposes a static “Instance” property which is easy to data bind to.

The class hooks into the view model document manager to provide its functionality. Thus, the Undo tool window can easily bind to the list of changes that need to be displayed:

<ListBox
ItemsSource=”{Binding UndoList,
         Source={x:Static documents:ActiveDocument.Instance}}” />

 

And similarly, the Properties tool window data-binds to a property of the active document’s view-model:

<!– Include data templates for the lifeline item view-models here
using resource dictionaries so that the right property-editor (baby, mortgage, etc) shows up –>
<ContentControl    VerticalAlignment=”Stretch

        HorizontalAlignment=”Stretch
        Content=”{Binding ViewModel.ActiveObject,
         Source={x:Static documents:ActiveDocument.Instance}}” />

 

MVVM Guideline #2: Don’t get stupid about following #1.

In actuality, my undo functionality is not as simple as a simple ListBox displaying a collection of undoable changes. Instead I wrote a custom WPF control understands that it is displaying undoable changes and knows how to invoke those undoable changes based on user actions. It is almost certainly possible that I could have done this using pure MVVM, but a user control was dramatically easier to implement. Sometimes, putting logic in the view layer is the right decision, especially when there’s a lot of user interaction based on clicking, selecting, selecting multiple items, or dragging. Like every other design pattern, MVVM is simply another tool in your toolbox that should be used with careful consideration and thought. I try and put as much code in the view models possible, but sometimes after thinking about how to do that I cannot come up with any elegant solution, and so I will resort to using a more “Windows Forms” programming style in those cases with code in the XAML code-behind.

However, it is been my experience that the majority of the time MVVM works quite nicely. For example, for my Properties tool window, the code sample above is my actual application code copy-and-pasted into this blog entry. Even the lifeline view (in the application screenshot above) is just XAML using MVVM with a very simple data binding:

    {Binding LifelineItems}
						

Advertisements

No comments yet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: