UPDATE: Minor changes thanks to some feedback from Glenn.
This is a post I am long overdue in making (yes, Glenn, I am finally getting to it!). For the last 4 months, I’ve been working about a week a month in between consulting and training gigs for Microsoft patterns and practices, helping to develop and architect Prism, which is the codename for a Composite WPF guidance package we have been working on. I can’t take too much credit considering I have only been dedicating 1/4 time or so to the project, the bulk of the work has been done by the p&p Prism team. Plus, Adam Calderon from Interknowlogy recently joined them as another outside WPF expert, and is filling the void nicely since I didn’t have enough time to give them.
What is a Composite UI Application?
Basically Prism is looking to address most of the same concerns that led to the development of the Composite UI Application Block (CAB) and the Smart Client Software Factory (SCSF). Specifically, if you have a large, complicated smart client application, particularly one developed by multiple (possibly distributed) teams, you can’t afford to build it all into one big monolithic mass of UI code in a single or small number of top level windows and their code behind. You will need to modularize the application and compose the UI that the user sees out of smaller, more granular and well factored parts that are as decoupled as possible from one another, but come together to make the end result without an overly complex integration effort.
To a small degree, you can pull this off by simply decomposing your UI into user controls to partition the functionality across a number of these mini-screens that compose the UI. But even with that approach you typically end up with a complicated mess of interdependencies and communication paths between the individual parts.
To do it right, you need to apply a number of patterns for composing your top level UI out of individual modules and views, each of which is decoupled from each other and composable themselves. This is what we are setting out to make easier with Prism. CAB and SCSF actually did a very good job of this for Windows Forms, and can be used for WPF as well. However, CAB and SCSF had a number of negatives to them and also don’t fully leverage the capabilities of WPF. As a result, we started with a clean slate with Prism and are not simply porting CAB. We are trying to leverage concepts and patterns that worked well in CAB, while strictly avoiding those that were overly cumbersome. We are also not reusing any code, with the goal of not being tainted by any of that past work and led down the “it was good enough” mentality that plagues many porting efforts.
What is it?
So what is Prism, or at least, what will it be when it ships? Prism is a guidance deliverable, which is acombination of written guidance documentation, sample code, and the beginnings of what could become a “framework” some day. If you have been exposed to other p&p offerings such as Enterprise Library or Smart Client Software Factory, you will find it easier to understand what we will be shipping. Most of the effort so far has been focused on developing a “Reference Implementation” or RI, which is a sample application that represents a real world application that is more than a simple demo, but less than a huge sample like Dinner Now. Specifically, it is sample application that demonstrates the core concepts and coding patterns of the project, and that allows those to be teased out while trying to build something semi-real. While building that and refining the patterns, we also factor out as much reusable stuff as possible into a set of class libraries that could be considered the beginnings of a framework for building composite WPF applications.
By the time we ship, Prism will also contain documentation that includes overview information of goals and challenges, design patterns, how-to topics, documentation on the RI, and documentation on the reusable parts (the framework), as well as QuickStarts. The QuickStarts are smaller sample apps that demonstrate just one aspect of what Prism offers, often a pattern or piece of code that we recognize as a common need for composite apps, but not one that we can really incorporate into the RI without making it seem like a confusing mishmash of unrelated stuff. These too will be covered in the documentation. The frameworky pieces are designed so that they are usable in isolation – you don’t have to adopt all of Prism to use part of it (one of the big downsides of CAB).
The key thing here is to provide stuff that makes building well designed composite WPF applications as easy as possible. However, I do have to caution you: building composite decoupled complex applications is… well, complex. We can help make it easier, but we can’t make it easy. You are still going to have to do the work of figuring what the right levels of decomposition and decoupling are for your app and your dev team, and then learn how to apply the patterns that we are fleshing out and demonstrating for you. This will not be a push a button, read your mind, and pop out a fully implemented application tool. It will be more like a do-it-yourself guide for building these kinds of applications.
What is in Prism today?
p&p runs a very agile shop. We develop with a Test-Driven Development (yes, even test first to the degree possible) approach, short iterations (2-3 weeks), and ship frequently (current goals and performance are to release a code drop with each iteration). As a result, our code drops on each iteration are publicly available through the Prism Codeplex side. We welcome anyone who wants to start playing with or using the early bits to do so and give us feedback on what you like or don’t like.
So far, Prism is mainly the RI, which is a stock trading application scenario. It is not very fully functioned, and has to only deal with dummy data for legal reasons yadda yadda. But it does incorporate a number of the features we have been working on.
The things in the RI so far include:
- UI Patterns – we have Model-View-Presenter (MVP), Presentation Model (aka Model-View-ViewModel MVVM or just View Model), and a couple kinds of controllers in the RI and QuickStarts so far.
- Modular decomposition – we are factoring out different pieces of functionality into different modules to represent the way a distributed team or multiple teams would likely decompose the work and allocate responsibility to different teams for different parts of the UI. The modular approach allows them to work more in isolation, minimizing dependencies and the need for shared source code access and check out (reducing source control contention). We are not yet doing dynamic modular loading like CAB does, but that is definitely in the backlog (to-do list).
- Views – The UI composition is all based around the definition of views, which are granular piece of the overall “screen” that you are putting together. We have examples of simple views, which can be defined as a custom control, user control, or even just a data template, as well as composite views, which have child views and possibly regions contained within them.
- Regions – this is the term we have settled on for something that is similar to what CAB called a Workspace. It is basically a container or location in the UI that modules can inject their views. For a decoupled composite app, you absolutely need these at a shell level so that the shell (top level window) does not have to have intimate (or any) knowledge of the contents that are provided by the modules. They can also be important down inside a composite view that is contributed by a module, so we are working on support at that level as well.
- Commands – for decoupled composite UIs, the built-in routed commands of WPF are insufficient because they are inextricably tied to the visual tree of your application. As a result, you get stuck in focus hell if you try to use them when your command handling logic lives anywhere other than at the root of your visual tree. To provide a more decoupled approach that will work across views and modules, we have implemented a commanding approach that is based on the ICommand interface of WPF, but with a different implementation.
- Dependency Injection (DI) – Also known as Inversion of Control (IoC), this becomes critically important for both breaking dependency chains when unit testing, and in the context of Prism, for allowing objects to be resolved without having object references passed explicitly all over the place, which breaks down the decoupling that you strive for in a composite app. Prism supports using multiple different DI containers. We are primarily using Unity, which is a new DI container developed by p&p, but you can also use Castle Winsor, StructureMap, Spring.net, or possible others.
- Services – Services in Prism are not SOA web services, but rather decoupled chunks of functionality that can be used across multiple models. We are using services for getting data into our presentation models (with dummy data), as well as for some of the common functionality such as region management, commands, and eventually event brokering.
- Custom Controls – to present some of our data in the way that we wanted, we needed some custom controls. Luckily we were able to steal a set of them from another Microsoft product team. They are not fully featured or production ready, but they are a starting point you can look at if you need to develop similar controls.
There is probably a few other key things in there that I am not thinking of off the top of my head, but hey, this post is getting long enough as it is.
So if you are in or moving into the WPF space, and if you are building large, enterprise scale apps with large or distributed teams, I’d encourage you to check out Prism and stay tuned for when we eventually release. I think you will find it will help accelerate your WPF development.