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
package, which is a fancy term for a combination 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 p&p parlance for 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).
-
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.
Wrap up
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.