• Migrating Composite Application Guidance (Prism-v2) to XBAP

    Published by on March 11th, 2009 11:23 pm under Uncategorized

    2 Comments

    I’ve seen that there are quite a few questions on how to use Composite Application Guidance for WPF and Silverlight  (a.k.a Prism) with XBAP applications on the discussion list, so I’ll try show you in this post how to migrate the HelloWorld demo (included with CAL) to XBAP.  If you are in a hurry, you can skip directly to the Solution.

    Problem

    The main issue is that XBAP applications rely on WPF framework to create the NavigationWindows that will be holding XBAP pages and CAL needs to create the main window on the Bootstrapper (creating instances of NavigationWindows is not allowed in PartialTrust applications).

    The first thing that you will  do to convert your WPF application into an XBAP application is changing <Window> for <Page> in you XAMLs. In most scenarios that is practically all you have to do because WPF framework is intelligent enough to create the right environment for the application: If you are using Windows, it just creates a new instance of a window and calls it’s Show method (like you usually do in the CAL’s Bootstrapper). But if you are using Pages, it needs to host pages in NavigationWindows or the Browser.

    But, if you are using CAL after changing your Windows for Pages, you will end up commenting the call to the Show Method (pages don’t have a Show method) and setting the starupURI of the application. And that’ were the root of the problem lies: WPF creates an instance of a Page and you are creating another instance in the Bootstrapper. That will mess up things and you will end up loosing references to the CAL’s regions and contentControls.

    Solution

    Based on Mokosh’s Prism and WPF Browser Application (Xbap) post that shows a good way run Prism v1 solution as XBAPs,  let’s migrate a Prism v2 solution to run as an XBAP application is as follows:

    We will start with the HelloWorldDemo.Desktop Quickstart included in Prism v2.

    1. Set the shell as the startup page of the application. To do that, open the App.xml file and add StartupUri=”Shell.xaml” to the <Application> element.
      <Application x:Class=HelloWorld.App
      xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
      xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
      StartupUri=Shell.xaml>
        <
      Application.Resources>
        </
      Application.Resources>
      </
      Application>
    2. In the App.xaml code behind (App.xaml.cs) remove the OnStartup method. We will add the BootStrapper initialization afterwards.
    3. In the Shell.xaml file change the <Window> element for a <Page> element. You should end up with the Shell.xaml code as follows:
      <Page x:Class=HelloWorld.Shell
      xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
      xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
      xmlns:cal=http://www.codeplex.com/CompositeWPF
      Title=Hello WorldHeight=300Width=300>
        <
      ItemsControlName=MainRegion/>
      </
      Page>
    4. In the Shell.cs make Shell inherit from Page instead of Window. Ej: public partial class Shell : Page
    5. To avoid creating a new instance of the shell, get the one created during the Application startup.  A good place to do that is the Shell constructor.
    6. public Shell()
      {
          Bootstrapper bootStrapper = new Bootstrapper();
          bootStrapper.ShellPage = this;
          bootStrapper.Run();
      
          InitializeComponent();
      }

    7. Now we will need to add a property to the Bootstrapper class to have a reference to the Shell and  then return it in the CreateShell method. So the complete Bootstrapper code should be:
    8. class Bootstrapper : UnityBootstrapper
      {
          private DependencyObject shellPage;
          public DependencyObject ShellPage
          {
              get
              {
                  return shellPage;
              }
      
              set
              {
                  shellPage = value;
              }
          }
      
          protected override DependencyObject CreateShell()
          {
              return ShellPage;
          }
      
          protected override IModuleCatalog GetModuleCatalog()
          {
              ModuleCatalog catalog = new ModuleCatalog()
                  .AddModule(typeof(HelloWorldModule.HelloWorldModule));
              return catalog;
          }
      }

    9. Press F5 and Enjoy!

    Further improvements:

    clip_image002 clip_image004

    Technorati Tags: Patterns and Practices,Composite Application Guidance,WPF,XBAP,Prism,CAL
    kick it on DotNetKicks.com