PRISM (Composite WPF) is a project endorsed by Microsoft specifically targeted at WPF, and hosted on CodePlex. According to Glenn Block, a Technical Product Planner for Microsoft, PRISM offers the following benefits:
o Provides complete support for WPF
o Dynamically composes user interface components
o Application modules are developed, tested and deployed by separate teams
o Allows incremental adoption
o Provides an integrated user experience
Right now, PRISM “includes a reference implementation, a reusable library code and pattern guidance”, but the plan is to develop a framework which composite applications can be built upon.
The Microsoft Patterns & Practices Team created the Prism CodePlex Project. Prism is a set of assets for developing Composite WPF applications. Prism includes a reference implementation, reusable library code and pattern guidance. Using Prism enables designing a composite application that is composed of many discrete, loosely coupled modules.
- Composite WPF
- Composite Application Guidance for WPF
Prism is a set of guidance coming out of Patterns and Practices for building composite applications in WPF.
Composite Application – It’s essentially an application that is dynamically composed from a set of different pieces
How different Prism is from CAB?
In one sense very different because Its not taking one line of code from CAB into Prism, so it’s a completely new effort. The reasoning for that is several fold: one reason is that WPF is entirely different than WinForms, completely different paradigm, the technology is different. There is a lot of things in CAB that have to reinvent the wheel because there was no similar construct in WinForms, but now actually things like commanding, for example, is build in to WPF. So for that reason plus combined with a large amount of feedback that microsoft p&p team got from customers who use Smart Client Software Factory which built on top of CAB and CAB, about how difficult it was to grok the number of abstractions, the fact that it was very imposing. I really had to accept every aspect of it which brought along a bunch of heaviness with it, and also it required me to build from scratch. So we’ve got costumers that are extremely happy with CAB and SCSF, but even the people that have been very happy have had a bunch of pains getting there, so we felt for that reason that we had a chance to both address delivering the right kind of guidance for the technology, being WPF, and at the same time to address the concerns that we heard from many customers
Components Mappings – CAB and PRISM
CAB Commands – Replaced with WPF Commands. See the Commanding Quick Start.
CAB EventTopics – See the IEventAggregator Service interface in the Events Quick Start.
CAB Items – Again replace with DI Container of your choice.
CAB Services – Service dependencies are resolved the DI Container similar to CAB.
CAB Smart Parts – Lots of options here – Any WPF User control can be a smart part or you can simply display a model with an associated DataTemplate (an approach I favor). Separated presentation parts are again wired through the DI container.
CAB State – Personally I never used this much in CAB, but you can resolve global state through the DI container if you wish.
CAB UIExtensionSites – with WPF’s flexibility a module can just add new items to a menu/toolbar without extra functionality. It could be a Comp WPF region.
CAB WorkItems – You can create you own hierarcy of containers, but Comp WPF seems to favor simply one container. What’s more important is to segment you business logic. See WorkItem controller below.
CAB Workspaces – Comp WPF uses regions and Region Manager Service. You can name regions in your XAML with an attached property.
PRISM Technical & Design Concepts.
1. Bootstrapper – The bootstrapper is responsible for the initialization of an application built using the Composite Application Library. Having a bootstrapper gives you more control of how the Composite Application Library components are wired up to your application. For example, if you have an existing application that you are adding the Composite Application Library to, you can initialize the bootstrapping process after the application is already running.
In a traditional Windows Presentation Foundation (WPF) application, a startup Uniform Resource Identifier (URI) is specified in the App.xaml that launches the main window. In an application created with the Composite Application Library, it is the bootstrapper’s responsibility. This is because the shell relies on services, such as the Region Manager, that need to be registered before the shell can be displayed. Additionally, the shell may rely on other services that are injected into its constructor. For more information about the shell, see the Shell and View technical concept.
The Composite Application Library includes a default abstract UnityBootstrapper class that handles this initialization using the Unity container. Many of the methods on the UnityBootstrapper class are virtual methods. You should override these methods as appropriate in your own custom bootstrapper implementation. If you are using a container other than Unity, you should write your own container-specific bootstrapper.
2. Container and Services – The Composite Application Library is designed to support other dependency injection containers. Core services, such as the ModuleLoader service, are container agnostic. They use the Composite Application Library container or IContainerFacade interface for resolving, instead of directly accessing the containers. The Composite Application Library provides the UnityContainerAdapter, which is a Unity-specific implementation of this interface. This container is registered by the UnityBootstrapper.
3. Module – A module in the Composite Application Library is a logical unit in your application. Modules assist in implementing a Modularity design. These modules are defined in such a way that they can be discovered and loaded by the application at run time. Because modules are self-contained, they promote separation of concerns in your application. Modules can communicate with other modules and access services through various means. They reduce the friction of maintaining, adding, and removing system functionality. Modules also aid in testing and deployment.
4. Region - Conceptually, a region is a mechanism that developers can use to expose Windows Presentation Foundation (WPF) controls to the application as components that encapsulate a particular visual way of displaying and laying out views. Regions can be accessed by name and support adding or removing views. This decoupling allows the appearance and behavior (look and feel) of the application to evolve independently of the views that appear within the region (for more information about views, see the Shell and View technical concept).
Regions are intended to enable a compositional pattern and are commonly used in template layouts and multiple view layouts.
5. Shell and View – The shell is the main window of the application where the primary user interface (UI) content is contained. The shell may be composed of multiple windows if desired, but most commonly it is just a single main window that contains multiple views. The shell may contain named regions where modules can add views. It may also define certain top-level UI elements, such as the main menu and toolbar. The shell also defines the overall appearance and behavior (look and feel) for the application. It may define styles and borders that are present and visible in the shell layout itself, and it may also define styles, templates, and themes that get applied to the views that are plugged into the shell.
Views are the composite portions of the user interface that are contained in the shell’s window(s). It is easiest to think about a view as a user control that defines a rectangular portion of the client area in the main window. However, views in the Composite Application Library do not have to be defined with a user control. You can use a Windows Presentation Foundation (WPF) data template to define a view that will be rendered based on the data in your model. A view could also share screen real estate with other views due to the rendering and compositing capabilities of WPF. In simple terms, a view is just a collection of user interface elements that define part of the rendering of the user interface. It is a unit of encapsulation for defining the separable portions of your UI.
6. EventAggregator -The EventAggregator service is primarily a container for events that allow decoupling of publishers and subscribers so they can evolve independently. This decoupling is useful in modularized applications because new modules can be added that respond to events defined by the shell or, more likely, other modules.
In the Composite Application Library, EventAggregator allows subscribers or publishers to locate a specific EventBase. The event aggregator also allows for multiple publishers and multiple subscribers
7. Commands - Commands are a way to handle user interface (UI) actions. They are a loosely coupled way to bind the UI to the logic that performs the action.
When building composite applications, presentation design patterns such as Model-View-Presenter (MVP) and Model-View-Controller (MVC) are often used to separate the UI logic from the UI layout and presentation. When implementing these patterns with Windows Presentation Foundation (WPF), the presenter or controller handles commands but lives outside the logical tree. WPF-routed commands deliver command messages through UI elements in the tree, but the elements outside the tree will not receive these messages because they only bubble up or down from the focused element or an explicitly stated target element. Additionally, the WPF-routed commands require a command handler in the code behind.
The Composite Application Library introduces two new commands that can be routed outside the boundaries of the logical tree and that do not require handling logic in the code behind. The commands are custom implementations of the ICommand interface defined by WPF, and they implement their own routing mechanism to get the command messages delivered to objects outside of the logical tree. The commands in the Composite Application Library include DelegateCommand and CompositeCommand.
8. Communication – When building large complex applications, a common approach is to divide the functionality into discrete module assemblies. It is also desirable to minimize the use of static references between these modules. This allows the modules to be developed, tested, deployed, and updated independently and forces loosely coupled communication.
When communicating between modules, you can use commanding, event aggregation, or shared services. Use the following to help decide which approach to use:
• Commanding. Use this in response to user gestures and custom enablement.
• Event aggregator. Use this to publish an event across modules.
• Shared services. Use this if neither of the preceding is applicable
1. UI Composition – Composite applications typically compose their user interfaces (UIs) from various loosely coupled visual components, otherwise known as views, to deliver an integrated application experience. To the user, the application appears as a seamless program that offers many capabilities
2. Modularity - Modularity is designing a system that is divided into a set of functional units (named modules) that can be composed into a larger application. A module represents a set of related concerns. It can include components, such as views or business logic, and pieces of infrastructure, such as services for logging or authenticating users. Modules are independent of one another but can communicate with each other in a loosely coupled fashion.
A composite application exhibits modularity. Imagine an online banking program. The user can access a variety of functions, such as transferring money between accounts, paying bills, and updating personal information from a single user interface (UI). However, behind the scenes, each of these functions is a discrete module. These modules communicate with each other and with back-end systems such as database servers. Application services integrate components within the different modules and handle the communication with the user. The user sees an integrated view that looks like a single application
3. Container – Applications based on the Composite Application Library are composites that potentially consist of many loosely coupled modules. They need to interact with the shell to contribute content and receive notifications based on user actions. Because they are loosely coupled, they need a way to interact and communicate with one another to deliver the required business functionality.
To tie together these various modules, applications based on the Composite Application Library rely on a dependency injection container. The container offers a collection of services. A service provides functionality to other modules in a loosely coupled way through an interface and is often a singleton. The container creates instances of components that have service dependencies. During the component’s creation, the container injects any dependencies that the component has requested into it. If those dependencies have not yet been created, the container creates and injects them first.
In some cases, the container itself is resolved as a dependency. For example, modules will often register views of the container by having the container injected.
There are several advantages of using a container:
• A container removes the need for a component to have to locate its dependencies or manage their lifetime.
• A container allows swapping the implementation of the dependencies without affecting the component.
• A container facilitates testability by allowing dependencies to be mocked.
• A container increases maintainability by allowing new services to be easily added to the system.
In the context of an application based on the Composite Application Library, there are specific advantages to a container:
• A container injects module dependencies into the module when it is loaded.
• A container is used for registering and resolving presenters and views.
• A container creates presenters and presentation models and injects the view.
• A container injects the composition services, such as the region manager and the event aggregator.
• A container is used for registering module-specific services, which are services that have module-specific functionality.