Click here to Skip to main content
15,888,527 members
Articles / Desktop Programming / WPF
Article

Sofa and Prism

Rate me:
Please Sign up or sign in to vote.
4.17/5 (6 votes)
27 May 2011CPOL5 min read 34.3K   1.8K   24   3
Sofa and Prism integration

Previously in Code Project

AvalonDock is a WPF controls library which can be used to create a docking layout system like that is present in Visual Studio.

It supports fly-out panes, floating windows, multiple docking manager in same window, styles and themes. Sofa embeds AvalonDock in a WPF UserControl and this allows integrating it in applications as easily as any other advanced UserControl, a DataGrid for instance.

A previous article in CodeProject introduced Sofa, AvalonDock and MEF.

Introduction

This article is about Prism integration. The example is a remake of the StockTraderRI, the Prism Reference Implementation: We first used this application to demonstrate Sofa can be used in any framework and we added it to a Prism RegionManager before moving some Prism modules from the RegionManager to Sofa. This Sofa-Prism Reference Implementation places Sofa at the heart of the application and shows how to dynamically create content in 2 SofaContainers. We kept most of the structure of the StockTraderRI application as well as its Shell and one of its modules. So, however the ultimate goal of this text is to introduce Sofa and Prism, most of it is about Prism.

The Pitch is Very Simple

The user can select a ticker symbol and the target container that will show news about it.

Image 1

Articles are shown in the selected SofaContainer and all features of the Sofa/AvalonDock libraries can be used. The 2 SofaContainers have their own behaviors: The left one creates only 1 instance of the News module and updates it as the right one creates a new instance of the News module for each call.

The cast features 5 actors, including 2 twins:

  • The Shell and the bootstraper are the foundation of the application.
  • The Infrastructure module mainly contains all commons elements.
  • The CommandBoard will show the comboboxes allowing selections and the button to open the news.
  • The 2 SofaContainers will host the News module.
  • The News module is a copy of the one used in the StockTraderRI, the Prism reference implementation.

We reused it to demonstrate any piece of code can be used as a Sofa component (and also because we are a bit lazy…).

Image 2

Here a picture of actors in Visual Studio:

Image 3

There are also 2 supporting roles:

  • Prism offers a set of facilities allowing not to worry about a lot of plumber concerns.
  • MEF will be in charge of implementing the usual dependency injection and inversion of control patterns.

Relationships of actors:

  • The bootstraper must have a reference on all other modules, mainly to initialize the MEF catalog.
  • All modules needing a resource stored in the Infrastructure have a reference on it.

And that's it: Modules do not have references on each other; this is the base of the composite application architecture.

Dialogs Will Use the Usual MEF Words

A class [Export] and other(s) [Import]. There are many examples in the SofaPrismRI example, this one shows the [Export] of the View of a Sofa component and the [Import] in the ViewModel of a SofaContainer:

Export of a Component

C#
[^__strong__^Export("Sofa.Examples.SofaPrismRI.ViewContract", typeof(UserControl))]
[PartCreationPolicy(CreationPolicy.NonShared)]
[ExportMetadata("ProductName", "ArticleView")]
public partial class ArticleView : UserControl
{…
- and Import in a Container
[ImportMany("Sofa.Examples.SofaPrismRI.ViewContract")]
public Lazy<UserControl, ISofaComponent_Metadata>[] MefViews { get; set; }
{…

The plot is driven by Prism and Sofa communication:

When a user clicks on the "Load document" button:

=> Action 1 - Inside a module: Prism DelegateCommand

The action of the button is a Prism DelegateCommand. The Prism ICommand interface implementation will manage the communication inside the CommandBoard module, from the View to the ViewModel.

Prism documentation: The DelegateCommand allows you to trigger a command at a point in the visual tree and handle it at a higher level… To create a delegate command, instantiate a DelegateCommand field in the constructor of your view model, and then expose it as an ICommand property.

The DelegateCommand will send the information from the View to the ViewModel.

=> Action 2: Between 2 modules: Sofa Prism EventAggregator

When the ViewModel receives the command, it must send it outside of the CommandBoard module without knowing who will catch it. The right tool for this is the EventAggregator.

Prism Documentation: This mechanism, based on the event aggregator service, allows publishers and subscribers to communicate through events and still do not have a direct reference to each other … Publishers raise an event by retrieving the event from the EventAggregator and calling the Publish method. To access the EventAggregator, you can use dependency injection by adding a parameter of type IEventAggregator to the class constructor.

Then any modules, here the 2 SofaContainer modules, can subscribe to the Prism EventAggregator event.

SofaContainers will have 3 tasks: First register the News as a Sofa Component, then create an instance of it and at last inform the instance of the value of the ticker symbol to show.

The 1st task has been done when initializing the Sofacontainers. Using MEF Sofacontainers ViewModels have imported references to the News module seen here as a Sofa component:

C#
[ImportMany("Sofa.Examples.SofaPrismRI.ViewContract")]
public Lazy<UserControl, ISofaComponent_Metadata>[] MefViews { get; set; }

Then the Lazy MefViews was used while setting the ViewModel as DataContext of the SofaContainer View to register Component(s):

C#
foreach (var view in ViewModel.MefViews)
{
     sofaContainer.RegisterComponent(view);
}

The 2nd task of a SofaContainer consists in instantiating the News module. This is done in the ViewModel, using the very simple OpenComponent method.

C#
CmpLoaded cmpLoaded = SofaContainer.OpenComponent("ArticleView");

Then the selected ticker symbol must be sent to the newly created News instance:

=> Action 3: Between Sofa Components: Sofa SofaCommon event

The 3rd task will be achieved using the SofaCommon event. It will send the ticker symbol value to the new instance and allows filtering on the GUID of the News instance so that not all instances update their content with the latest selected ticker symbol.

C#
 SofaContainer.RaiseSofaCommonEvent
(cmpLoaded.GUID, "TickerSymbolSelectedEvent", callForOpenDocumentParameters);

Note: The Prism event mechanism associated to Subscription Filtering can also be used in place of the SofaCommon events.

At last, the ViewModel of the News module handles the Sofa SofaCommon event raised by the SofaContainer and calls the loadTickerSymbol method that triggers the display of the News.

A Few Things We Learnt

  • Prism avoids the need to write complex syntax about Dependency properties or Routed command: Not all developers are WPF tightrope walkers (I don't think I am), however they are asked to produce robust code in a short time and this is maybe the main advantage of Prism.
  • The News module of the StockTraderRI application was reused in the SofaPrismRI application with a very few modifications. Let's be sincere: Most of the developers spend most of their time recycling previous code. Prism may help them a lot!
  • We did not face complex debugging. This is related to Composite Application architecture and this way of developing becomes obvious when you have used it once: Code, don't debug.

History

  • 27th May, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionBasic concepts Pin
Rajiv Verma4-Oct-11 23:30
Rajiv Verma4-Oct-11 23:30 
AnswerRe: Basic concepts Pin
Sofa Team6-Oct-11 2:01
Sofa Team6-Oct-11 2:01 
Have a look at the Sofa web site.
There you will find the main download including a "Hello World" example and a chm help file as well as some documentation.
GeneralMy vote of 1 Pin
snortle27-May-11 10:05
snortle27-May-11 10:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.