Prism / Dependency Injection for Windows Phone 7

by 14. January 2011 23:42

If you are looking for Prism functionality for Windows Phone 7 you may want to visit our open source Password Manager application on CodePlex (http://PasswordMgr.CodePlex.com).

The objective of porting Prism to Windows Phone 7 was to provide a platform that can be used identically on Desktop, Silverlight and Windows Phone 7 operating systems so that I could have a single code base using the Project Linker (May 2010).   Since Prism is available for both Desktop and Silverlight all I had to be concerned with was  Windows Phone 7.   The Prism for Windows Phone RC on CodePlex lacked Dependency Injection support and only provided a few classes - this was not going to do for our purposes.

Important note: Our primary goal is to create a single code base that supports multiple platforms.  Our efforts with porting Prism 4 and Unity to the phone platform will be limited to this objective; we will not be investing time/energy into building up the Unity feature set beyond our needs as this time is needed to complete the framework and Password Manager application.

A key component that I was missing was Unity, a Dependency Injection (DI) container that Prism 4 is designed to work with (as well as MEF).  Without this DI container there would be no port (MEF is not supported on both Silverlight and WP7 so this was not an option).  Since the latest word on Unity for WP7 was "there would be no port" I had to improvise.  I grabbed the Container Model, DI container, from the Mobile Application Blocks and imported it into my Gwn.ContainerModel.Mobile (WP7 project). 

Unit Testing

It was time to roll up my sleeves and port over all of the Prism and Container Model unit test, this posed a unique problems since I needed the test to run against the Windows Phone 7 code, not the desktop code.   My solution is shown in Fig 1. below:

  1. I copied Prism.Desktop files into Gwn.Prism4.Mobile (two left panes below)
  2. I copied Prism.UnityExtensions.Desktop into Gwn.Prism4.Mobile\UnityExtensions folder so I didn't have to manage two projects.
  3. I created a Gwn.Prism4.Desktop project that was linked to the Gwn.Prism4.Mobile project (two middle panes below).
  4. I created my Gwn.Prism4.Desktop.Tests and pointed it to my linked code in Gwn.Prism4.Desktop (code resides in Gwn.Prism4.Mobile).
  5. I followed the same steps for the Gwn.ContainerModel.Desktop.Tests

I was starting this port under the notion "if it compiles, it will run".

Emulating Unity with the ContainerModel

Getting Prism 4 to compile required us to provide components it needed, such as ObjectBuilder2, ServiceLocation and Unity classes. As the compiler complained I would pull the classes from the applicable source and place it in a folder, within the Gwn.ContainerModel.Mobile project, that corresponded with the namespace. When the smoke settled I was pleasantly surprised that most of the Prism 4 framework remained and compiled successfully.

There were some component methods, such as RemoveAll() in the image below, that I had to create because they didn't exist in the .Net WP7 environment. Since the unit test were running against the ported code I had a reasonable amount of confidence that if the unit test passed that my manual updates were successful.

 As of changeset 81886, of the Password Manager on CodePlex, there are 727 test that successfully pass against the original Prism4/ContainerModel test fixtures.   As is the goal with Test Driven Development (TDD) I had a lot of failing test that I needed to make work.   Most of the test revolved around the Unity container; up to this point I was only concerned with getting it to compile so along the way I created a UnityContainer class (that implements IUnityContainer) which had a lot of empty methods that simply threw exceptions.   You'll find that there are still empty methods in the UnityContainer because I only concerned myself with the methods that were required to pass the unit test.

I started by instantiating the ContainerModel DI container on line 11 (which was passing all of it's unit test) and then updated each called method to utilize the _container class.    I then had to update each failing method to perform the functionality that was required to successfully pass the test (reference RegisterType method below).

Along the way I found there were a number of null references because the ContainerModel DI container does not support constructor injection.  This required me to update each Prism 4 class that relied on constructor injection to ensure each constructor parameter was supported with setter injection;  I moved each parameter into a property with a [Dependency] attribute above it.   I then had to update the Resolve methods to ensure that as each class was resolved that it performed a BuildUp() which ensured its properties, marked with the DependencyAttribute, were initialized.

MVPVM: Integration testing using the Presenter

by 20. June 2010 12:17

The MVPVM pattern lends itself to effective integration/unit testing.   Since their is no code in the code-behind and the Presenter processes all business logic against the ViewModel and View it is the best component to perform integration test against. 

In the following application (download from this link DirectoryLookupModularity.zip (5.82 mb)) there are three view models:

  1. CriteriaViewModel - utilized by views E, B and C
  2. DoctorViewModel - utilized by view A
  3. PatientViewModel - utilized by view D

The MVPVM framework used for the attached application consistently uses the following for bootstrapping modules:

The ModuleBase<TPresenter> (see below image) instantiates the specified Presenter, e.g., on line 14 below we identify the "DoctorPresenter" as the presenter.

The PresenterBase<TView, TViewModel> (see below image) specifies the View and it's ViewModel which in this case is DefaultViewA and DoctorViewModel respectively.  On line 23 we register the view (DefaultViewA) with the TopLeft region which was declared in the Shell's XAML.  The remaining logic is the code required to wire-up a CRUD control and to get the current module load counter value so that we can see that the module dependency attributes are working correctly.

These baseclasses do all of the wiring up so that we can focus on business rules; we don't spend a lot of time getting our module up and ready for the requirements at hand.

The integration test for Module A's presenter is shown below (lines 46-52); it verifies that the infrastructure properly wired up the View and ViewModel. 

Did you notice that on line 24 above we set the container to null and on the following line use the container.RegisterServices() method?   On the surface this may look odd but it lends itself to testing the Prism environment.

We use the same RegisterServices in our bootstrapper as we do in our integration/unit test - we do this to ensure our environments match for testing purposes.  To accomplish this we use a IUnityContainer Extension class (IUnityContainerExtension), the only time container will be null is during testing so we instantiate a MockBootstrapper (lines 25-27 below).   From that point on we have the same registrations to ensure our test will run without complaint.

MSBUILD Copy Task - Upgrading PRISM to Unity 2.0

by 29. January 2010 22:07

To ensure that the application's infrastructure is not obsolete before it is completed I am using the newest techologies available (VS2010, Azure, PRISM, MEF, Unity, etc).  

The process that follows will ensure all Third-Party libraries are built and available for the new EHR application. 

Unity 2.0 and MEF Beta 2 are not yet released but I'll want to take advantage of their new features.  When they are released I'll have to perform this process again so I'll simplify it now.  Since PRISM is dependent on Unity I'll have to upgrade it so that it is compatible with Unity 2.0.  There are no dependencies on MEF but some changes have to be made because Beta 2 clashes with the version of MEF that resides in .NET 4.0.

Once I get all issues resolved so that the various projects and solutions will build I'll use a MSBuild's Copy task to transfer the .DLLs to a unified Binaries folder (c:\_\source\Binaries\Desktop).  My EHR application will reference this Binaries folder as required. 

I could simply place the ItemGroup and Target element directly into the applicable projects but it will be far easier to create a "CopyToBin.Desktop.Targets" file and reference it with one line of code. 

 

 

[CopyToBin.Desktop.Targets] contents follow: 

http://msdn.microsoft.com/en-us/library/3e54c37h.aspx

 

<Project DefaultTargets="AfterBuild"

    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>

      <AllDll Include=".\**\*.dll" />

    <CopyToBin Include="c:\_\source\Binaries\Desktop"/>

  </ItemGroup>

 

  <Target Name="AfterBuild">

    <Message Text="Processing Copy Task"/>

      <MakeDir Directories="@(CopyToBin)"/>

      <Copy

          SourceFiles="@(AllDll)"

          DestinationFolder="@(CopyToBin)"  />

  </Target>

</Project>

 

I'll place the .targets files in the root of my source folder (where all my third-party source code files reside).

To easily edit the project file simply right click on the project and "Unload" it.  Once unloaded you can right click on the unloaded project and select "Edit" (reference right pane in the image below).   Note that I have a snippet in my Toolbox so that I can simply go to the end of the project file and insert the location of my CopyToBin.Desktop.Targets file.   I'll then "Reload" the project

I'll do the above steps for all of the Unity projects and then build the project.   The resulting DLLs will be copied to the Binaries\Desktop folder where I can now transfer them to the applicable PRISM folder.

PRISM stores the Unity files in it's LIB\Desktop\Unity folder.  You'll have to delete the existing files and copy the newly created Unity DLLs from the Binaries folder to the above PRISM folder (later I'll have a batch file do this).

You are now ready to load the PRISM solution and compile it.  There are only a few differences in Unity 1.2 and Unity 2.0 that will break the build.

  1. Two projects will complain that you require a reference to System.Xaml (assuming you are also upgrading PRISM to VS2010).
  2. There are a few Mock objects that do not implement interfaces correctly - simply implement the interfaces as applicable.
  3. There will be two sections where you'll have to remark out code for objects that no longer exists (this is okay - I verified it with the PRISM team)

You should now be able to build PRISM using the newly compiled Unity 2.0 DLLs.

Note: To build MEF under VS2010 you'll need to follow the few steps I noted in the MEF Developers forum (CLICK HERE)

Once I have all of my projects setup with the new CopyToBin.Desktop.target I can run the batch files I created.   The first, BuildBinaries.cmd, will launch the Visual Studio 2010 command window - its contents follow:

@ECHO OFF
echo Type - and hit ENTER
call %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"" x86

This batch file is the one provided by Visual Studio which sets up the environment (otherwise the second batch file won't find MSBuild).   It effectively opens a Visual Studio Command window so that you can easily run the second batch file "-.cmd"  (dash - keep it quick/simple). 

The -.cmd batch file is based on folder structures compatible with the third-party applications.  The batch file will change directories to each of the applicable solutions and then run MSBuild against it.

Note: I renamed the folders since doing the above screenshot to ensure I wouldn't have to modify the batch file later (I'll just simply ensure updates use the names used).

The end results is a I have a Binaries folder that is populated with all of the Third-Party DLLs that I will be using for my application.  When new releases are provided I simply have to ensure they compile and then run my batch file again.

Creating Desktop Skins in WPF for PRISM Desktop

by 13. August 2009 10:14

Based on Creating a Skinned User Interface in WPF (excellent blog on the topic!), adapted for PRISM and dependency injection.

Creating SKINS in WPF Desktop for PRISM is relatively easy.   The first thing we want to do is create our styles.  Note in my WPF Project (Demo.WPF second arrow) that I use an Assets folder - this is to be consistent with the .NET RIA Services auto generated styles (top arrow). 

My Styles.xaml file will contain styles common to all skins - in this case I have a StylesDefault (Blue) and StylesGreen (Green).

With the Styles (skins) out of the way we can start wiring up PRISM.   We do this by Loading both of the Stylesxxxxx.xaml files and registering them in our Container - the type will be ResourceDictionary with the names set to "Blue" and Default".  The code for the Windows.cs (Shell) follows:

   22 /// <summary>
   23 /// Interaction logic for Window1.xaml
   24 /// </summary>
   25 public partial class Window1 : Window
   26 {
   27     /// <summary>
   28     /// Load resources delegate
   29     /// </summary>
   30     public delegate void LoadResourcesDelegate();
   31 
   32     [Dependency]
   33     public IUnityContainer Container { get; set; }
   34 
   35     [Dependency]
   36     public ILoggerFacade Logger { get; set; }
   37 
   38     public Window1()
   39     {
   40         InitializeComponent();
   41 
   42         this.Loaded += new RoutedEventHandler(Window1_Loaded);
   43     }
   44 
   45     void Window1_Loaded(object sender, RoutedEventArgs e)
   46     {
   47         // Load asynchronously
   48         Dispatcher.BeginInvoke(new LoadResourcesDelegate(LoadResources));
   49     }
   50 
   51     private void LoadResources()
   52     {
   53         // Load secondary styles when the XAML Build Action
   54         // is set to "Content"
   55         Container.RegisterInstance<ResourceDictionary>("Blue",
   56             (ResourceDictionary)Application.LoadComponent(
   57             new Uri("Assets/StylesGreen.xaml", UriKind.Relative)));
   58 
   59         // Load default styles (so we can restore).  The XAML
   60         // Build Action is "Page" - required because the App.XAML
   61         // shows this as the MergeDictionary
   62         Container.RegisterInstance<ResourceDictionary>("Default", 
   63             (ResourceDictionary) Application.LoadComponent(
   64             new Uri("Assets/StylesDefault.xaml", UriKind.Relative)));
   65     }
   66 }

Note how we are loading the skins on their own thread (line 48).  We don't have an immediate need for the skins since our App.xaml code is loading the StylesDefault.xaml resources for it's own use (line 8 below); we don't have to affect performance by loading skins on the UI thread.

    1 <Application x:Class="Demo.WPF.App"
    2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    4 
    5     <Application.Resources>
    6         <ResourceDictionary>
    7             <ResourceDictionary.MergedDictionaries>
    8                 <ResourceDictionary Source="Assets/StylesDefault.xaml"/>
    9             </ResourceDictionary.MergedDictionaries>
   10         </ResourceDictionary>
   11     </Application.Resources>
   12 
   13 </Application>

At this point we have successfully loaded our skins into our Unity Container and are ready to wire-up a view to utilize them.

We'll now go to our Modules folder and select the ModuleClient.WPF (WPF for Desktop) and wire-up our MenuRegion's view (MainMenu) to process the available skins.  Note below we create a context menu with two menu options "Blue" (default) and "Green".

Our code behind will handle the ContextMenu_Click by using the EventAggregator to raise a MenuItem click event (ClickEventArgs handles MenuItem, Button and CheckBox clicks).   We're done on the UI side - now we'll turn our attention to the Presenter which will handle the click event.

The PrismContrib.xxxx assemblies abstract much of the framework from us (KISS).   Within these libraries resides the PresenterBase<T> which wires everything up on lines 27-32.   Once wired-up we have virtual methods that we can override to simplify our lives, e.g., below we override the OnButtonClickEventHandler to handle our MenuItem click.

The magic happens on lines 45 and 50 as applicable.  They utilize a Extensions class which extends the IUnityContainer interface.  Note how we can use the same code (line 29 below) for both Silverlight and WPF Desktop by using the "using" statements on lines 5 and 7 (below).

Line 26 will resolve our ResourceDictionary by the name effectively giving us a reference to the applicable skin dictionary.

On line 29 we get a reference to the current resource and clear it on line 33.   All that remains is to add our updated MergedDictionary and walla!  We have successfully applied a new skin.

    1 using System.Windows;
    2 using Microsoft.Practices.Unity;
    3 
    4 #if SILVERLIGHT
    5 using wpfCollection = System.Windows.PresentationFrameworkCollection<System.Windows.ResourceDictionary>;
    6 #else
    7 using wpfCollection = System.Collections.ObjectModel.Collection<System.Windows.ResourceDictionary>;
    8 #endif
    9 
   10 
   11 using System.Collections.ObjectModel;namespace Infrastructure.Resource
   12 {
   13     /// <summary>
   14     /// Resource Utility
   15     /// </summary>
   16     public static class ResourceUtil
   17     {
   18         /// <summary>
   19         /// Sets the skin.
   20         /// </summary>
   21         /// <param name="rd">The rd.</param>
   22         /// <param name="skinName">Name of the skin.</param>
   23         public static void SetSkin(this IUnityContainer container, string skinName)
   24         {
   25 #if !WinForm
   26             ResourceDictionary skin =
   27                 container.Resolve<ResourceDictionary>(skinName);
   28 
   29             wpfCollection mergedDicts =
   30                 Application.Current.Resources.MergedDictionaries;
   31 
   32             if (mergedDicts.Count > 0)
   33                 mergedDicts.Clear();
   34 
   35             // Apply the selected skin so that all elements in the
   36             // application will honor the new look and feel.
   37             mergedDicts.Add(skin);
   38 #endif
   39 
   40         }
   41     }
   42 }

Right clicking on the Menu bar (top sky-blue region) reveals our context menu. 

Tags: , ,

WPF

Unity 2.0 update - comprehensive error reporting! Important in PRISM/DI environment.

by 7. August 2009 02:43

I keep my finger on the pulse of Microsoft's newest technologies and updates; I typically find that they make my life a lot easier by helping me to be more productive for my clients.   The latest Unity 2.0 updates did not disappoint!

On THIS LINK (image below) you'll find the following information on the Unity 2.0 update which is currently available for download in the http://www.codeplex.com/Unity downloads area:

Anyone having to troubleshoot an enterprise level application that uses dependency injection will appreciate the new power provided to us.  In my case I use the PRISM framework and have spent my fair share of time locating errors caused by a failure to register a dependency.

THIS WEBCAST shows that within a few minutes (literally) we can track down and resolve (no pun intended) an issue.

 

SL3 TabItem HeaderTemplate does not support DataBinding - PRISM work-around

by 6. August 2009 09:18

An excerpt from this message thread on Silverlight.net follows:

TabControl and Databinding is a sore point for a while now. You can show your support in fixing it on this codeplex bug:
http://silverlight.codeplex.com/WorkItem/View.aspx?WorkItemId=3604 

We're planning on overhauling TabControl for the Silverlight vNext release.

Sincerely,

--
Justin Angel,
Blog @ http://silverlight.net/blogs/JustinAngel
Twitter @ http://twitter.com/JustinAngel

The problem reveals itself in the PRISM View Injection QuickStart: 

Since PRISM has a TabcontrolRegionAdapter for Silverlight we have a hook into the problem (for a work-around).  Excerpt from documentation on the BootStrapper follows:

Conditional compiling is used to register the TabControlRegionAdapter only for Silverlight. This is because when you add an item in a TabControl control in WPF, this item is wrapped inside a TabItem type. This is not applicable for Silverlight, where you must manually wrap the item into the TabItem; because of that, the TabControlRegionAdapter adapter was modified to both adapt a region to the TabControl control and to automatically add this wrapping.

PRISM users can update the TabControlRegionAdapter.cs, in the Composite.Presentation project, as follows:

private static TabItem PrepareContainerForItem(object item, DependencyObject parent)
{
TabItem container = item as
TabItem;
if (container == null
)
{
    container = new
TabItem();
    container.Content = item;
    container.DataContext = GetDataContext(item);
    container.Style = GetItemContainerStyle(parent);
    container.SetValue(IsGeneratedProperty, true
);

    // BillKrat.2009.08.06 - SL3 Template binding bug workaround

    if (container.Header != null
         && container.Header.ToString().Contains("Binding:"
))
    {
     PropertyInfo modelProperty = null
;

     // Strip "Binding:" from the header - leaving model property

     string modelPropName = container.Header.ToString().Replace("Binding:", ""
);

     // Get model properties and search for the property name provided

     PropertyInfo[] propInfo = container.DataContext.GetType().GetProperties();

    
if (propInfo != null
)
        modelProperty =
         propInfo.FirstOrDefault(p => p.Name.ToString() == modelPropName);

     // If found then update the header with the value

     if (modelProperty != null
)
        container.Header = modelProperty.GetValue(modelProperty, null
);
    }
}

return
container;
}

Instead of using Value="{Binding HeaderInfo}", which won't work under SL3, you can use "Binding:HeaderInfo" which will be processed by the above method.  (note: Header will be set/available when the container.Style property is set above).  An example follows:


<Regions:TabControlRegionAdapter.ItemContainerStyle>
    <Style TargetType="Controls:TabItem">
        <Setter Property="Header" Value="Binding:HeaderInfo"/>
    </Style>
</Regions:TabControlRegionAdapter.ItemContainerStyle>

Until the Silverlight Toolkit team resolves the issue this can serve as a work-around.   With some work it could be made more dynamic but this is a good starting point.

 

The model being used follows:

namespace UIComposition.Modules.Project
{
    public class
ProjectsListPresentationModel
    {
        public ObservableCollection<BusinessEntities.Project> Projects { get; set
; }

        public static string
HeaderInfo
        {
            get { return "Current Projects"
; }
        }
    }
}

EDITED - a better solution was provided on the following link.  Although I haven't tested it yet I was impressed that it resolves the problem with one line of code - my kind of fix!   I found the above to be a great learning exercise in the power of styles so I leave it intact as is.

PRISM User forum addressing the issue HERE

Does PRISM have a performance issue?

by 31. July 2009 22:21

A developer in the PRISM forum was noting that the Shell (main app) loaded a control faster than a view (injected into a region) could load the very same control.   As THIS DEMO will verify the user control loaded much faster within the shell (bottom) and took up to five seconds to load within a module's region (top).   Once I refactored his code you will see that not only does the control load very fast but also the application (patience will be required for the demo code it is very slow).

His comment follows:

I'm working on a simple demo application using the compoiste Application Library for WPF. I have an issue in that when I inject a user control into a region in the shell there is a considerable lag in the control rendering and being visible. When I include the same control in the shell (not in a referenced IModule) it appears instantly. I understand that I must take a performance hit at the point when I load controls into my shell from other modules but the delay is quite extreme. The control itself is a dataGrid (WPFToolkit) with around 2000 rows - there is no database work being done to generate the data for the grid.

Is there any reason Im getting such poor performance? The lag in the control rendering is around 5 seconds - a complete show stopper for using prism if it cannot do something so simple. more

Source code provided by developer demonstrating the issue: CALDemoOld.zip (2.13 mb)
Refactored source code using best Practices and Patterns (P&P): CALDemo.zip (3.50 mb)

There were some inherent design flaws that introduced this issue; which have nothing to do with PRISM (as shown by the demo link above).

The following control is the topic of this discussion - note how in the code-behind that we are populating TestEntities with 1000 elements and then applying it to the data context.


Figure A. 

Below is the XAML for the Shell - note that it simply references the Control.   When the Shell is loaded the code (above) will execute effectively populating the control within the Shell.


Figure B. 

As you can see below in the sequence diagram the CreateShell process (which actually does a Shell.Show()) will execute, and display the control long before the InitializeModules() command fires (which will place the same control within the MainRegion above).   So this explains the increased performance for the Shell's load of the control


Figure C. 

So what about the lengthy delay?   If you were to put a break point after InitializeModules you would find that the Shell's control is visible and populated while the Regions control is still not visible - our processing logic within the controls code-behind is bogging down the UI thread. 

What we need to do is pull the Data Access Layer (populating 1000 elements) out of the presentation layer and have it process asynchronously on a separate thread.   In the case of my refactored code I update the model which the MainRegions control is databound to.

Applying the Model-View-Presenter (MVP) pattern against the control we now only have to have the following code to populate our model (which the view is bound to).  The PresenterBase subscribes to an event raised in the Bootstrapper when modules are initialized so that it can start the asych process of populating the model.TestEntities property (handled by OnProcessEvent below).  Since model.TestEntities is an observableCollection WPF will automatically be notified as the collection changes - which is why we pass it in as a parameter after every 15 elements we allow event processing to continue which effectively will refresh our Grid display every 15 elements (more on this below).


Figure D.

Below is our refactored BootStrapper which launches a new thread to handle the data processing


Figure E.

Note how on line 17 of Figure D above that we are using Dependency Injection (DI) to get our data access layer.   In the Services folder we implement IEntityDataService using stubbed data - later the actual data layer could eaily replace the "stub" by simply updating the modules Initialize method to reflect the new implementation - in the case of this demo we are using EntityDataStub.

public void Initialize()
{
    container
        .RegisterType<
IMyControl, MyControl>()
        .RegisterType<
IEntityDataService, EntityDataStub>()
        .RegisterType<
IMyControlPresentationModel, MyControlPresentationModel>(
        new ContainerControlledLifetimeManager()); // Singleton

Notice on line 21 below we are borrowing a feature from System.Windows.Forms.   The Application.DoEvents() method permits other events to process.  In the absence of this the below process is hogging up the CPU cycles and will not give other events a chance to process until it is completed - on lengthy delays your form could "stop responding".  As a result of this command our grid will refresh every 15 elements which will be reflected by the behavior of the scrollbar.

Architectural note:  This demo uses a combination of the Model-View-Presenter (MVP) pattern and the Model-View-ViewModel (MVVM) pattern, aka Presentation Model and Application Model.    By having multiple views share the same model (see Martin Fowlers Presentation Model) you can effectively share the same data without having to have a lot of complex logic to maintain state.   Each view can update the model and the other views will be notified via the observer pattern (INotifyPropertyChanged).

Trying to use MVVM alone has introduced the limitations that Martin Fowler discussed in THIS ARTICLE (paragraph above Figure 11).   As he suggest, it was the limitations that introduced the need for MVP.   Combining them gives us the best of both worlds.  

 

How to use .NET RIA Services in PRISM

by 27. July 2009 21:20

For Webcast overview of process CLICK HEREImportant note: the Presenter being shown on the screen during the Webcast is actually being utilized by the Silverlight, RIA, WPF and Winforms applications (they all utilize the PRISM framework using the Model-View-Presenter and Model-View-ViewModel patterns - see architectural note at end of blog). 

Tim Heuer's presentation on RIA services for Silverlight 3
http://silverlight.net/learn/learnvideo.aspx?video=245417

Tim Heuer does an excellent presentation of RIA services on the above link.   The problem for PRISM developers is that the RIA data access layer resides in the presentation layer’s bootstrap application RIABusApp (ref image below).   Since our RIABusApp will reference our module(s) this poses a problem because now our modules cannot reference our RIA data layer (which resides in RIABusApp) because of a circular reference.   The key to making real RIA work with PRISM is to be able to have the modules reference the bootstrap application RIABusApp.

Fortunately Silverlight allows us to load assemblies dynamically.  With a few lines of code we can load the module and call its initialize mapping without ever having made a reference to the Module.  This is practical with PRISM because most of the business logic will reside in a module minimizing the requirement for any references in RIABusApp.

Code follows:

using System;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Unity;
using PrismContrib.Base;
using PrismContrib.Events;
using PrismContrib.Interfaces;

namespace RIABusApp
{
    public partial class App : Application
    {
        private IBootstrapperProcess bootstrapperProcess = null;

        [Dependency]
        public IUnityContainer Container { get; set; }
        private IUnityContainer container; 

        public App()
        {
            this.Startup += this.Application_Startup;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        void Application_Startup(object sender, StartupEventArgs e)
        {
            this.Resources.Add("RiaContext", RiaContext.Current);
            Bootstrapper<MainPage> bootstrap = new Bootstrapper<MainPage>();
            bootstrap.OnConfigureContainer += OnConfigureContainer;
            bootstrap.OnInitializeModules += OnInitializeModules;
            bootstrap.InitParams = e.InitParams;
            bootstrap.Run();
        }
        /// <summary>
        /// Dynamically load the Mapping Module because it will have
        /// a reference set to this assembly to gain access to the
        /// Services\DataLayerDefault class
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="PrismContrib.Events.BootStrapperEventArgs"/>
        /// instance containing the event data.</param>
        void OnInitializeModules(object sender, BootStrapperEventArgs e)
        {
            container = e.Container;
            WebClient client = new WebClient();

            client.OpenReadCompleted +=
                new OpenReadCompletedEventHandler(OnAssemblyOpened);

            // Requires assembly to be in the RIABusApp.Web ClientBin folder
            client.OpenReadAsync(
                new Uri("ISO15926.Module.Mapping.Silverlight.dll", UriKind.Relative));
        }
        void OnAssemblyOpened(object sender, OpenReadCompletedEventArgs e)
        {
            AssemblyPart assemblyPart = new AssemblyPart();
            Assembly assembly = assemblyPart.Load(e.Result);

            // Find our mapping module in the list returned by GetTypes
            Type mappingType = assembly.GetTypes()
                .First(m => m.FullName.Contains("MappingModule"));

            // Dynamically instantiate our module
            IModule module = (IModule) Activator.CreateInstance(mappingType);

            if (module != null)
            {
                // Buildup doesn't seem to be working on dynamically
                // created class...  Will set container manually
                // => container.BuildUp(module);
                ((IContainer)module).Container = container;
                module.Initialize();
            }
        }

        void OnConfigureContainer(object sender, PrismContrib.Events.BootStrapperEventArgs e)
        {
            e.Container.RegisterType<IControlProcessor, ControlProcessorWPF>();
        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // a ChildWindow control.
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled.
                // For production applications this error handling should be replaced with something that will
                // report the error to the website and stop the application.
                e.Handled = true;
                ChildWindow errorWin = new ErrorWindow(e.ExceptionObject);
                errorWin.Show();
            }
        }
    }
}

The application that we're using for this blog is a multi-targeting application; this means that we can have multiple platforms using the same code (as shown in the projects underlined above).  In this case RIA Services will be utilizing the Silverlight module.  Below you'll see all of the client side code that is required to return a class list, as Tim noted in his presentation all of the projection is handled for us.

The code on server side is no more complicated as shown below.

In PRISM, because of dependency injection, all we have to do to consume our service is request a reference to IDataService (constructor injection), request the classes and assign the results to the model.Classes property.

Note: The SemWeb infrastructure (which utilizes my own PRISMContrib project) handles the event notification for us.   SemWeb is scheduled to be released late August at http://www.CodePlex.com/SemWeb.

The source code for the MappingPresenter follows: 

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using ISO15926.Library;
using ISO15926.Module.Mapping.Services;
using Microsoft.Practices.Unity;
using Microsoft.Windows.Controls;
using PrismContrib.Base;
using PrismContrib.Events;

namespace ISO15926.Module.Mapping.Views.InformationModel
{
    /// <summary>
    /// Information Model presenter
    /// </summary>
    public class InformationModelPresenter : PresenterBase<IInformationModelView>
    {
        private ISemWebPresentationModel model;

        private DataGrid grdClasses {
            get { return GetControl<DataGrid>("dgClasses"); }
        }

        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="InformationModelPresenter"/> class.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="model">The model.</param>
        /// <param name="container">The container.</param>
        /// <param name="riaDAL">The ria DAL.</param>
        public InformationModelPresenter(
            IInformationModelView view,
            ISemWebPresentationModel model,
            IUnityContainer container,
            IDataService riaDAL) : base(view, model, container)
        {
            this.model = model;

            // Populate model with ISO15926 Class
            model.Classes = riaDAL.GetClassList();
        }

        private void OnDataLoaded()
        {
            grdClasses.ItemsSource = model.Classes;
        }

        #region OVERRIDES of baseclass methods  

        #region METHOD: OnViewSizeSet
        /// <summary>
        /// Called when [view size set].  Sets the data grid dimensions
        /// to the current view
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.SizeChangedEventArgs"/> instance containing the event data.</param>
        protected override void OnViewSizeSet(object sender, SizeChangedEventArgs e)
        {
            // Filter for this view
            IInformationModelView view = sender as IInformationModelView;
            if (view == null)
                return;

            // Set grid height and width to view dimensions so that
            // we'll have scrollbars
            grdClasses.Height = e.NewSize.Height;
            grdClasses.Width = e.NewSize.Width;

            base.OnViewSizeSet(sender, e);
        }
       
        #endregion
        #region METHOD: OnButtonClickEventHandler
        /// <summary>
        /// Handles all Button/CheckBox Click events
        /// <see cref="E:ClickEventHandler"/>
        /// </summary>
        /// <param name="e">The <see cref="ClickEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnButtonClickEventHandler(ClickEventArgs e)
        {
            e.IsHandled = e.Name.Contains("DetailsView_ClickMe");

            if (e.IsHandled)
                MessageBox.Show(string.Format("ISO159296 Classes record count = {0}",
                        model.Classes.Count));

            base.OnButtonClickEventHandler(e);

        }
       
        #endregion
        #region METHOD: OnDALEventHandler
        /// <summary>
        /// Raises the <see cref="E:DALEventHandler"/> event.
        /// </summary>
        /// <param name="e">The <see cref="PrismContrib.Events.DALEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnDALEventHandler(DALEventArgs e)
        {
            // We're only interested in IsLoading context property changes
            if (e.IsPropertyChange && e.PropertyName.Contains("IsLoading"))
            {
                if (!e.IsLoading)
                {
                    e.IsHandled = true;  // notify logging we handled it
                    base.OnDALEventHandler(e);
                    OnDataLoaded();
                }
            }
            else  // For logging purposes
                base.OnDALEventHandler(e);

        }
       
        #endregion       
        #region METHOD: OnModelPropertyChanged 

        /// <summary>
        /// Called when [model property changed].  Intended to be overridden
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/>
        /// instance containing the event data.</param>
        public override void OnModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
#if !SILVERLIGHT
            // WPF/WinForms are using stub data so there is no callback method
            // to trigger OnDataLoaded() - we'll fire it manually on
            // ModelPropertyChanged
            if (e.PropertyName.Contains("Classes"))
                OnDataLoaded();
#endif
        }
       
        #endregion        

        #endregion
    }
}
 

Architectural note:  This application uses a combination of the Model-View-Presenter (MVP) pattern and the Model-View-ViewModel (MVVM) pattern, aka Presentation Model and Application Model.    By having multiple views share the same model (see Martin Fowlers Presentation Model) you can effectively share the same data without having to have a lot of complex logic to maintain state.   Each view can update the model and the other views will be notified via the observer pattern (INotifyPropertyChanged).

Trying to use MVVM alone has introduced the limitations that Martin Fowler discussed in THIS ARTICLE (paragraph above Figure 11).   As he suggest, it was the limitations that introduced the need for MVP.   Combining them gives us the best of both worlds.  

 

Silverlight and WPF - CompositeWPF/Prism supports multi-targeting (single shared codebase)

by 6. March 2009 11:00

Source Code available at http://www.Codeplex.com/SDMS 
Project Linker Blog w/Webcast HERE  

A recent Microsoft Codeplex forum interaction had me updating the SDMS application so that the Employee Module and all of it's views were Multi-targeting (worked on both Desktop and Silverlight).  The reasoning follows below: 

Developer writes "I'm not looking for multi-targeting support, I just want an SL app that uses WCF and is maintainable and testable."

My response follows:

I don't think they are mutually exclusive - I believe you may want/need multi-targeting support.   Let me explain by example - I just spent the last couple of hours updating the SDMS application so that the Modules folder is supported under both Desktop and Silverlight.  Why?   "maintainable and testable".   I created a Unit Test for you and checked everything in (been really wanting to do this for a while and this gave me good reason to).

The key point here is that the "only" code that will be different will be the XAML (Silverlight/WPF) and the actual WCF Service call.  I did however create my Desktop WCF Service using Async communications so you won't find any SILVERLIGHT conditional statements anywhere in the Business Logic Layer or Data Layer (they are one and the same code for both sides).   I should give a plug for the Project Linker (blogged about on my blog site w/webcast); all my time was spent creating empty WPF views and implementing the interface on them.

[TestMethod]

public void TestMethod1()

{

    // IModule does all of the heavy lifting - configures all interfaces

    // so we'll just use it to set things up.

    IModule module = Container.Resolve<IModule>();

    module.Initialize();

 

    // Resolve the EmployeeList Presenter

    EmployeeListPresenter MockView = Container.Resolve<EmployeeListPresenter>();

 

    // Give WCF Service a chance to complete

    Thread.Sleep(2000);

 

    // Cast so we can easily access presentation model

    EmployeePresentationModel model =
             (EmployeePresentationModel) MockView.Model;

 

    Assert.AreEqual(3, model.EmployeeList.Count,
                   "Employee list should have three records!");

}


Note we can put the Testing thread to sleep :)  I just tested everything short of the UI which is databound to the presentation model (nothing to test in the view) all the way through the WCF Service and back.  Since my PresentationModel implements INotifyPropertyChanged I can rest assured my View will work (assuming I did my Binding correctly).

Let's see what IModule was up to (showing the effectiveness of multi-targeting)

 

 

public class ModuleEmployee : IModule

{

    // For class use

    private readonly IUnityContainer container;

    private readonly IRegionViewRegistry regionViewRegistry;

 

    /// <summary>

    /// Constructor : Setup class

    /// </summary>

    /// <param name="container"></param>

    /// <param name="regionViewRegistry"></param>

    public ModuleEmployee(IUnityContainer container,

        IRegionViewRegistry regionViewRegistry)

    {

        this.container = container;

        this.regionViewRegistry = regionViewRegistry;

    }

 

    public void Initialize()

    {

        RegisterViewAndServices();

 

        // EmployeeModule - Views folder

        regionViewRegistry.RegisterViewWithRegion("MainRegion",

            () => container.Resolve<EmployeeMainPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("frmCaption",

            () => container.Resolve<frmCaptionPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("frmEmployeeList",

            () => container.Resolve<EmployeeListPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("TabInformation",

            () => container.Resolve<EmployeeInformationPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("TabAssigned",

           () => container.Resolve<EmployeeAssignedPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("TabInWork",

           () => container.Resolve<EmployeeInWorkPresenter>().View);

 

        regionViewRegistry.RegisterViewWithRegion("frmStatus",

            () => container.Resolve<frmStatusPresenter>().View);

 

    }

 

    private void RegisterViewAndServices()

    {

        container.RegisterType<IEmployeeMainView, EmployeeMainView>()

 

            // Layers

            .RegisterType<IEmployeeProviderBLL,EmployeeProviderBLL>()

            .RegisterType<IEmployeeProviderDAL,EmployeeProviderDAL>()

 

            // Views

            .RegisterType<IfrmStatusView, frmStatusView>()

            .RegisterType<IfrmCaptionView, frmCaptionView>()

            .RegisterType<IEmployeeListView, EmployeeListView>()

            .RegisterType<IEmployeeListView, EmployeeListView>()

            .RegisterType<IEmployeeInWorkView, EmployeeInWorkView>()

            .RegisterType<IEmployeeAssignedView, EmployeeAssignedView>()

            .RegisterType<IEmployeeInformationView, EmployeeInformationView>()

 

            // Services

            .RegisterType<IEmployeeService, EmployeeService>()

 

            // Models

            .RegisterType<IEmployeePresentationModel, EmployeePresentationModel>(

                            new ContainerControlledLifetimeManager());

    }

}

}


It did some pretty heavy lifting which tells me everything that will be executed during Silverlight runtime - works. 

The following is the Presenter, which is responsible for updating the Presentation Model (which the view is observing).  You can see that my Desktop Unit Test effectively exercises many, if not all, logic within the process.  

 

Note: Silverlight unit testing is done in a browser...  I'd rather take this approach.

Hope this helps in your quest to finding an architecture that works for you!

Bill


 

public class EmployeeListPresenter : PresenterBase<IEmployeeListView>

{

    readonly IEmployeeService employeeService;

    readonly IEventAggregator aggregator;

    readonly IEmployeePresentationModel model;

 

    /// <summary>

    /// Constructor : setup class

    /// </summary>

    /// <param name="container"></param>

    /// <param name="view"></param>

    public EmployeeListPresenter(

        IEmployeeListView view,

        IEmployeePresentationModel model,

        IUnityContainer container,

        IEventAggregator aggregator,

        IEmployeeService service) : base(view,model,container)

    {

        this.aggregator = aggregator;

        this.employeeService = service;

        this.model = model;

 

        // Subscribe to ListBoxChanged event and

        aggregator.GetEvent<ListBoxChangedEvent>()
                  .Subscribe(ListBoxChangedEventHandler, true);

        aggregator.GetEvent<EmployeeEvent>()
                  .Subscribe(EmployeeEventHandler, true);

 

        // Async call to service to populate employee list. 
        // The EmployeeListEventHandler
will be called when
        // data is received

        employeeService.GetEmployeeList();

    }

 

    /// <summary>

    /// Subscribed to in constructor - updates the model's
    /// SelectedEmployee property every
time a new employee is selected

    /// </summary>

    /// <param name="args"></param>

    private void ListBoxChangedEventHandler(SelectionChangedEventArgs args)

    {

        model.SelectedEmployee = args.AddedItems[0] as Employee_Data;

 

        StatusBarEvent sbEvent = aggregator.GetEvent<StatusBarEvent>();

        if (sbEvent != null)

            aggregator.GetEvent<StatusBarEvent>().Publish(

                new StatusBarData

                {

                    Message = string.Format("You clicked {0}",
                                    model.SelectedEmployee.DisplayValue),

                    Panel = StatusPanel.Left

                });

    }

 

    /// <summary>

    /// Handler for when Employee list is returned by service call to

    /// GetEmployeeList()

    /// </summary>

    /// <param name="args"></param>

    private void EmployeeEventHandler(EmployeeEventArgs args)

    {

        model.EmployeeList = args.EmployeeList;

    }

 }

CompositeWPF/Prism - Adding modules after BootStrapper

by 27. February 2009 06:32

The following sequence diagram shows us that the InitializeModules() method is the last process run http://global-webnet.net/UML/prism.htm

Examining the baseclass code we find that the following is what actually loads the modules; suggesting that it is safe to run again because of  the statement in bold:

       private void LoadModuleTypes(IEnumerable<ModuleInfo> moduleInfos)
       {
            if (moduleInfos == null)
            {
                return;
            }

            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                if (moduleInfo.State == ModuleState.NotStarted)
   
             {
                    if (this.ModuleNeedsRetrieval(moduleInfo))
                    {
                        this.BeginRetrievingModule(moduleInfo);
                    }
                    else
                    {
                        moduleInfo.State = ModuleState.ReadyForInitialization;
                    }
                }
            }
            this.LoadModulesThatAreReadyForLoad();
        }


I did a quick Proof of Concept with the StockTraderRI application to see if it was as easy as what was suggested to add a module after the BootStrapper process;  I added the line in bold below to the App() class

namespace StockTraderRI
{
    public partial class App : Application
    {
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            //this.RootVisual = new Shell();
            var bootstrapper = new StockTraderRIBootstrapper();
            bootstrapper.Run();

            // Watch module will not load without this line
            bootstrapper.PostCatalogProcessing(); 
        }

I then updated the StockTraderRIBootstrapper as follows. 

namespace StockTraderRI
{
    public partial class StockTraderRIBootstrapper : UnityBootstrapper
    {
        protected override IModuleCatalog GetModuleCatalog()
        {
            var catalog = new ModuleCatalog();
            catalog.AddModule(typeof(MarketModule))
                .AddModule(typeof(PositionModule), "MarketModule");
                //.AddModule(typeof(WatchModule), "MarketModule");   <= remarked out
                //.AddModule(typeof(NewsModule));                                <= remarked out

            return catalog;
        }

        public void PostCatalogProcessing()
        {
            ModuleCatalog catalog = (ModuleCatalog)Container.Resolve<IModuleCatalog>();
           
            catalog.AddModule(typeof(WatchModule), "MarketModule");
            catalog.AddModule(typeof(NewsModule));
            InitializeModules();
        }

Notice

Blog videos and references to CodePlex projects are no longer valid