Introduction to UI Design Patterns for Windows 8 Apps
User interface (UI) design patterns are reusable solutions that have evolved to solve the problem of maintaining the presentation layer of your application independently of the underlying business logic, services, and data. Some of the problems being solved include the following:
- Fluidity of the user interface—Often there can be significant changes to look, feel, and interaction over time. A well-defined and properly implemented UI design pattern can help insulate those changes to minimize impact on the core business logic and data concerns. This is evident in the existing templates that can expose data in various views (snapped, landscape, and portrait) without having to change the underlying classes that provide the data.
- Parallel development and design—Often the design team is separate from the development team, with different skillsets and involving multiple designers. UI design patterns can maximize the efficiency of this workflow by providing the separation necessary to allow the developers and designers to work in parallel with minimal conflicts. Design-time data allows designers to work directly with the XAML to create the desired look and feel without having to understand or interact directly with the underlying logic.
- Decoupling of presentation logic—There are common patterns in the presentation layer, such as providing a list of items and allowing the user to select a single item, that can be solved in multiple ways (combo box, grid, list box, and so on). UI design patterns help decouple data elements from the presentation implementation so the core functionality can remain the same regardless of how the pattern is presented.
- View-logic testing—Complex view logic is often the domain of developers. Testing the logic is made easier by not requiring a full-blown UI. An example is dependent or cascading lists: Selecting an item in the first list determines the content of the second list. Ideally, you should be able to implement this behavior and test it without having to draw a corresponding combo box control and process click events.
In 2005, a developer named John Gossman working on WPF—which at the time was code-named Avalon—published a blog post that would ultimately introduce the MVVM pattern to the world (http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx). In his post he described “a variation of Model/View/Controller (MVC) that is tailored for modern UI development platforms where the View is the responsibility of a designer rather than a classic developer.”
The introduction to his post provides valuable insight into one of the original motivations for the pattern: the designer/developer workflow. His post further explains that the view is defined declaratively (a reference to XAML) and is responsible for inputs, keyboard shortcuts, visual elements, and more. The view model is responsible for tasks that are too specific for the general model to handle (such as complex UI operations), for maintaining the view state, and for projecting the model to the view, especially when the model contains data types that won’t map directly to controls.
MVVM uses data-binding and the Visual State Manager (VSM) to communicate between the UI implementation and your business and presentation logic. Instead of raising events, the view drives the view model through data-binding—whether it is by updating a value that in turn synchronizes to a property on the view model or by mapping an event to a command that fires on the view model. Presentation logic exists in the view model as code and takes the form of behaviors, triggers, visual states, and value converters in the view.
In applications based on the built-in Visual Studio 2012 templates, the LayoutAwarePage automatically detects changes to the view state (for example, going into snapped view or changing the orientation from portrait to landscape). The InvalidateVisualState method uses the VSM to set the new visual state:
string visualState = DetermineVisualState(ApplicationView.Value); foreach (var layoutAwareControl in this._layoutAwareControls) { VisualStateManager.GoToState(layoutAwareControl, visualState, false); }
In XAML, the VSM enables you to define the appropriate templates for the various states. You’ve learned how to provide a snapped view or how to switch from using the GridView control to a ListView control when the orientation changes. The design is defined in the XAML independently of the underlying code, creating a clean separation of concerns.
You can see what this looks like for the Wintellog project in Figure 1. Note the LayoutAwarePage facilitates the view model dictionary, handles changes with the VSM, and is the base class that the XAML for the view is derived from. The BlogDataSource class coordinates with the application to gather data and then exposes this via the view model dictionary, starting with the GroupList property.
Figure 1: The MVVM pattern used by the Wintellog application
Like other patterns, MVVM is a solution to common problems. When implemented correctly, it should make the job of building your Windows 8 application easier. Unfortunately, the pattern can be abused and end up slowing down projects and making them more complex than necessary. I’ve built dozens of large enterprise applications using the MVVM pattern and am glad that Microsoft decided to make the pattern a part of their built-in templates for Windows 8 apps. The first use of MVVM in Visual Studio dates even earlier to the Panorama templates used for Windows Phone development. Although the pattern has been used for years, there are many lingering misconceptions. Table 1 lists some of these misconceptions and the truth that addresses them.
Table 1: Common MVVM Misconceptions
Misconception |
Truth |
MVVM is extremely complex. |
MVVM can be incredibly simple when implemented correctly. |
Code-behind isn’t allowed in MVVM. |
Code-behind is simply an extension of the declarative XAML for the view. The view is responsible for managing the user interface, including user inputs, and there is no reason the code-behind cannot deal with events and interactions. |
MVVM is hard to implement. |
Many frameworks exist (for example, MVVM Light and Caliburn.Micro) that can enable you to have your project up and running in minutes, including the built-in Visual Studio 2012 templates for C# with XAML. |
MVVM eliminates the need for value converters. |
Value converters are reusable, testable pieces of code that can map data from the model to the view, and there is no reason to eliminate them when using the MVVM pattern. |
MVVM reduces the performance of the application. |
The improper implementation of any pattern can create performance issues. Proper use of MVVM facilitates unit tests that can help tweak and improve performance. |
MVVM is only good for very large projects. |
A good MVVM framework coupled with solid understanding is just as suitable for small projects as it is big ones. |
MVVM is about commands and messaging systems. |
MVVM simply specifies the responsibilities of various modules within the code. Commands, messaging frameworks, and other constructs are just helpers and building blocks. |
MVVM is hard to understand. |
MVVM is no more difficult to understand than data-binding and the Visual State Manager because it really is just a pattern that describes how best to use these features. |
In the rest of this chapter you learn about the various parts of MVVM and how to apply it with a special focus on testing. If you’ve read the previous chapters in this book and followed the examples, you already have an understanding of MVVM because you’ve created specific classes that implement property-change notification to facilitate data-binding. Those classes can actually be thought of as your view models. You also learn more about view models later in this chapter.
Contrary to the misconceptions about MVVM, there are many advantages the pattern provides above and beyond the separation of design from development. In my experience, these are the top ten benefits you may receive by using MVVM in your applications:
- A clean separation of concerns (decoupling)—MVVM follows best practices for software architecture.
- Designer/developer workflow—MVVM enables parallel development and design by multiple team members working on the same project through its support of design-time data.
- Unit testing—You learn more about testing later in this chapter.
- Use of data-binding—MVVM takes direct advantage of the rich and powerful data-binding system in XAML for Windows 8 apps, which also allows for design-time data.
- Improved code reuse—View models can be used to power multiple views, and various helpers and scaffolding can be reused throughout your project and across various products in your organization, even in different technologies including WPF and Silverlight.
- Modularity—MVVM encourages a modular design that makes it easy to modify parts of the application independently of each other.
- Refactoring containment—Through the clean separation of concerns, MVVM minimizes the impact to other areas of the application from refactoring.
- Extensibility—A well-designed MVVM framework makes it easy to extend the application by adding new screens and modules.
- Tools support—Various tools, such as Expression Blend and the designer, are built into Visual Studio that can take direct advantage of MVVM.
- Pattern vocabulary.
The final item, pattern vocabulary, requires some additional explanation. When you are learning how to read, there is a strong correlation between the size of your vocabulary and your ability to comprehend what you are reading. This should not be surprising because vocabulary provides the building blocks for the text you are trying to comprehend, and not understanding those blocks can lead to confusing conclusions and misinterpretations of the text. Although there is a strong correlation, vocabulary certainly doesn’t guarantee comprehension because you must be able to piece the words together and derive their meaning as a whole.
Developing software is an exercise that also involves a vocabulary. You start with the vocabulary of the language you are developing in. Programs have their own syntax and grammar, and comprehension relies on your ability to interpret the keywords correctly and understand them in context. Patterns provide a higher level vocabulary that can describe entire subroutines and components within the system. As with vocabulary, knowing a pattern isn’t the same thing as comprehending how it best fits into a software application (or whether it belongs at all).
The more you are able to understand and integrate patterns, the more you will be able to build your vocabulary and better comprehend complex software systems. I’ve found the developers who are involved in the most successful projects and who have tackled the most complex systems also tend to have a strong pattern vocabulary. They are not only aware of many patterns that exist in software development, but also understand when and where they make sense.
I believe MVVM is popular because it has been so successful at providing the benefits listed earlier when implemented correctly. MVVM is an important pattern to learn and understand for Windows 8 applications especially because it is the default pattern provided by the built-in C# with XAML templates. Like all patterns, it is a tool and must be used for the right job. In the next few sections I cover MVVM in more detail to help you learn the pattern and determine how to take advantage of it in your applications. Let’s start by examining the components that make up MVVM.