IgorShare Thoughts and Ideas

Consulting and Training

Office Applications via Prism of Unity

Posted by Igor Moochnick on 03/19/2011

This article was submitted to the MSDN magazine for publication 2 years ago. It wasn’t published due to budget cuts in the magazine and my small disagreement with Glen Block on the way I’ve used the bootstrappers. Glen was busy this time with MEF and we didn’t have time to resolve our differences.

So, for what it worth, it’s a great article and helped me and my teams in a lot of ways.

Now you’ll be the judge of that if you’ll keep on reading.

This article discusses:

  • VSTO – Visual Studio Tools for Office system
  • Prism v2 – December 19 drop 8 – Composite Application Guidance for WPF and Silverlight
  • Unity Application Block 1.2 – October 2008 drop
  • WPF
  • Visual Studio 2008 Sp1
  • Introduction

    Adding integration with Office suite was always a sweet fruit that only the daring people were willing to touch. This is mostly due to a different development model that the Office suite demands – you have to specifically target your functionality to work with Office applications and develop it separately from your main application. Office integration is based on COM knowledge. At the beginning, it was hard to wrap your head around the Office COM object model, but, with the release of the VSTO (Microsoft Visual Studio Tools for Office System), it became much easier to develop the integration for the .NET applications. The use of VSTO PIA (Primary Interpol Assemblies) makes it easier but does not change the paradigm very much: it is still necessary to develop separate application components that integrate into the Office suite. Until today, it has been hard to reuse and integrate parts of a primary product with the Office suite. We need a way to create GUI applications that can be easily decomposed into separate parts and components, and re-hosted in different ways and configurations. In other words: we need a way to create composite GUI blocks that can be hosted by Office applications and Windows applications equally.

    Note that the biggest benefits of creating composite applications in general, and for Office suite in particular, are maintainability and testability. Your components can be developed separately from each other by distributed teams and tested outside of the Office applications while maintaining high quality levels of the code. This greatly reduces the complexity of the development process.

    The Office Suite applications are, by nature, composite ones. They consist of a lot of different parts and services that have to intercommunicate and coexist in a common environment. Let us take Outlook as an outstanding example. It consists from many different parts, like folder trees, explorers (folder views), inspectors (item views), ribbons, form regions, configuration tabs, etc. All of those components have to be loaded, initialized and composed in a certain way. And do not forget that, after they are loaded, they have to communicate with each other and change their views and representations in reaction to the changes in the state of their peers.

    Let us see a simplified workflow of what happens when we change an active folder in Outlook to another one:

  • A new folder is selected in a folder tree
  • Toolbar is updated to enable or disable actions that are allowed in the selected folder
  • An active Explorer clears its current items list and populates it with the list of items from the new selected folder
  • A first item in the list is automatically selected, which causes the explorer to:
  • Update the toolbar to reflect actions that can be applied to the selected item
  • Locate an appropriate inspector that knows how to render the selected item and render it in an adjoined pane (to the explorer)
  • Locate the appropriate form regions that are associated with the selected item, create appropriate custom task panes and render them
  • Note how complex the described workflow is, and adding your own functionality into it brings certain challenges.

    Outlook is not alone in this case – all the other applications from the Microsoft Office Suite, in their own different contexts, have similarly complex workflows. All of them have menu bars, ribbons tool bars, panes, regions, etc. This leads us to the question: is there a way to solve these different complexities in a common way? The answer is Yes!

    Recently released Prism (i.e. the Composite Application Guidelines for WPF) is a perfect candidate to untangle such a tight logic knot and help us create simple composite applications that can play nicely with the applications from the Office suite. It describes how we can create composite applications from modular blocks and assemble then however we need. Furthermore, this broadens the horizons of the hosting solutions. This article will take you step by step through the implementation of an application that can be executed equally as a standalone or as a hosted one. We will see how it can be hosted within an Office application as well.

    A real life scenario

    Let us take a real life use case: we have a full-fledged stand-alone CRM application. We would like to integrate a portion of it, which manages customer lists, with the Office suite. To simplify our explanation we are going to use an extremely trimmed down version of the CRM application. We are going to limit it only to the customer management functionality (Customer Manager): i.e. presenting a list of the existing customers and their info. To simplify the case, our application is going to read the customer information from its local DB.

    If we design the application the way we used to – we will have a monolithic application. It is difficult–if not impossible—to integrate such an application with other applications. In order to make such integration possible, the main application should consist of separate modules and components. As we know, this is relatively easy to do with the utility classes, but not as easy with the GUI components. In order to make our application integration friendly, its GUI has to be cohesive and loosely coupled – in simple words, should consist of a set of integral parts and regions that can be easily decoupled but which fit snugly together.

    What is a composite GUI application?

    I am sure many people have heard this phrase before, but not everyone knows what it means, and, even less, how to create a composite GUI application.

    Cohesive, in relation to the software, refers to a combination of self-bonding parts creating an integral solution due to snug internal connections.

    This means that the components should fit together as the interlocking pieces in a puzzle.

    Many of us know how to make this happen with the utility classes –we use interfaces and plug-ins. As soon as a couple of classes implement the same interface – they can be easily exchanged. By using the plug-in model – this replacement can be done by using some configuration management infrastructure. However, what about GUI applications? How can you achieve the loose coupling and cohesion between the GUI elements: i.e. form parts and controls? The answer to this question is a simple one but complex in implementation.

    The Microsoft Patterns & Practices team has provided us with most of the solution for WPF applications. This includes a set of guidelines that describe how we can create the composite applications. In this article, we are going to concentrate, specifically, on Prism block: Composite Application Guidance for WPF and Silverlight.

    Those guidelines, if followed, allow us to make sure that all the UI parts become cohesive components. This, on its own, allows us to develop such parts in isolation from each other but, still be sure that they will fit snugly during the composition (or assembly) of the main GUI. This is, if you think about it, very useful for large and distributed development teams. The more loosely coupled the application, the more testable and maintainable it becomes.

    Composing an application

    In our example, the GUI for the Contact Manager is going to look like Diagram 1 :

    clip_image002

    Diagram 1: Visual Regions of the CRM application

    Notice the two distinct regions:

  • Customer List (left-side region) – allows the user to select a contact from a list.
  • Customer Info View (right-side region) – displays the customer info.
  • There is a third, non-visual component – a service that retrieves a list of customers and provides customer Info on demand. So, on a component diagram, our CRM application can be represented as shown in Diagram 2:

    clip_image004

    Diagram 2: Modular structure of the CRM application

    Here you can clearly see the three distinct parts and, following the guidelines for creating composite applications, we will create three distinct modules to better demonstrate the flexibility of the design:

  • CustomerManager.ListViewModule
  • CustomerManager.InfoViewModule
  • CustomerManager.Services
  • The first two modules instantiate the visual regions and the third one provides the customer information DB functionality.

    Later we are going to see that modularity of the application helps us seamlessly integrate our reference application with other hosting solutions, particularly with Office suite.

    Let us see what tools we have at our disposal.

    Unity – IoC/DI

    The flexibility of the composite applications can mostly be attributed to the extensive use of the IoC/DI Container. There are a lot of different implementations of Inversion of Control (IoC) and the Dependency Injection (DI) methodologies, but, since Prism heavily uses the Unity Application block, we will concentrate on Unity in this article.

    Inversion of Control (IoC) suggests that your components should avoid creating and initializing other components from its own code. They should ask some external component to do it for them – this is where the “inversion” of control comes from. The components delegate this function to somebody else who knows how to do it better. Better, because there may be much more to know about the initialization of the component to be created, i.e. dependencies and initialization configuration. In addition, since this information is kept outside of the scope of the components to be created, those dependencies can be substituted easily.

    This is where the Dependency Injection (DI) comes in. Since components depend on other components, which in turn depend on yet other components – resolving the dependencies during the initialization can become a very complicated task. This is where the extra knowledge about the components dependencies is required and where dependencies can be substituted and replaced. This can be driven by the desires of a developer, a customer, or the requirements of a particular deployment.

    Let us see a couple of simple examples of how you can use Unity IoC. This will be beneficial for understanding the rest of the article.

    To retrieve a class CustomerDataService that implements ICustomerDataService you call Unity IoC in the following way:

    interface ICustomerDataService { }
    class CustomerDataService : ICustomerDataService { ... }
    ...
    Container.RegisterType<ICustomerDataService, CustomerDataService>();
    ICustomerDataService customerList = container.Resolve<ICustomerDataService>();
    

    In this example, Unity IoC acts as a “service locator”. In this case, every time the Resolve is called, Unity creates a new instance of the CustomerDataService object. This is similar to calling “new” on the class. In cases where there is a need for a single instance of a certain object to exist in the current scope, Unity should be notified by registering it in the following way:

    Container.RegisterType< ICustomerDataService, CustomerDataService>(
           new ContainerControlledLifetimeManager());
    

    Unity will then take control of the lifetime management of the CustomerDataService instance, and make sure that it will look and act like a singleton (single instance in the scope).

    In cases where you already have an instance of an object, you can register it with Unity in this way:

    Container.RegisterInstance<icustomerdataservice>(new CustomerDataService());
    

    These were the examples of Unity as the Inversion Of Control Container. It is great in Dependency Injection as well. There are multiple ways to use the Dependency Injection functionality so I am going to show you the simplest but most commonly used one – the constructor dependency injection:

    interface ICustomerDataService { }
    class CustomerDataService: ICustomerDataService { }
    ...
    class CustomerInfoView  {
        private ICustomerDataService _customerDataService;
        public CustomerInfoView(ICustomerDataService customerDataService) {
            _customerDataService = customerDataService;
        }
    }
    ...
    var container = new UnityContainer();
    container.RegisterType&lt; ICustomerDataService, CustomerDataService&gt;();
    var customerInfoView = container.Resolve<customerinfoview>();
    

    In this case, the Resolve method of Unity will see that the CustomerInfoView class (constructor) depends on a CustomerDataService. Unity will notice the dependency, will create an instance of a CustomerDataService, and will pass it into the constructor of the CustomerInfoView during its creation. This is a short example of how you can register types with Unity and how you can still create instances of unregistered classes and have this nice dependency resolution (injection) happen.

    You can read more about Unity IoC and DI in the MSDN article, “Unity Application Block 1.2 – October 2008” (msdn.microsoft.com/en-us/library/dd203104).

    Developing a reference composite CRM application using Prism

    Let us get back to our real life scenario and see how we can, by following the Prism guidelines, implement a loosely coupled composite application.

    Four main features of Prism block that ship out of the box with the Composite Application library are:

  • UI Composition – dynamically add portions of UI and even make it configuration driven.
  • Modular loading
  • Commanding infrastructure – supplements the Routed commands in WPF
  • Loosely coupled events mechanism – another supplement to the Routed commands
  • For our composite CRM application, we are going to use the following Prism and Unity assemblies (more information on building the CRM reference application can be found in the readme.txt file attached to the sample code project):

  • Microsoft.Practices.Composite
  • Microsoft.Practices.Composite.UnityExtensions
  • Microsoft.Practices.Composite.Wpf
  • Microsoft.Practices.Unity
  • Microsoft.Practices.ObjectBuilder2
  • Microsoft.Practices.ServiceLocation
  • Following the Prism guidelines, we are going to start development of our application with a Bootstrapper, which should be inherited from the UnityBootstrapper. The bootstrapper is going to initialize a Unity IoC container as well as register all the participating modules. The UnityBootstrapper (part of the Prism application block) will load all the registered modules and will initialize them. This, in turn, gives these modules a chance to load their components and initialize internal services.

    The Bootstrapper initializes and shows a main shell window that becomes a host for the rest of the visual components.

    protected override DependencyObject CreateShell()
    {
       var shell = new Shell();
       shell.Show();
       return shell;
    }
    

    The shell window defines two distinct regions. Think of a region as a “declaration of intent” that we will be placing visual content in this area:

    </pre>
    <Window ... >
        <Grid>
            ...
            <ContentControl prism:RegionManager.RegionName="{x:Static Constants:RegionNameConstants.CustomerListView}" Grid.Column="0" />
            ...
            <ContentControl prism:RegionManager.RegionName="{x:Static Constants:RegionNameConstants.CustomerInfoView}" Grid.Column="2" />
        </Grid>
    </Window>
    

    Note that the names of the regions are not hard-coded but specified via constants that are residing in a referenced class library CRM.Infrastructure. This allows easier refactoring and, as we will see later, better reuse of the components.

    In the GetModuleCatalog method, the Bootstrapper registers all the required modules as well as their interdependencies:

    protected override IModuleCatalog GetModuleCatalog()
    {
        var catalog = new ModuleCatalog();
        catalog.AddModule(typeof(ServicesModule))
            .AddModule(typeof(ListViewModule.ListViewModule), "ServicesModule")
            .AddModule(typeof(InfoViewModule.InfoViewModule), "ServicesModule");
        return catalog;
    }
    

    You can see that the ListViewModule and InforViewModule depend on the ServicesModule.

    Let us see how the ListView module is built. The other one follows the exact same pattern.

    The registered GetModuleCatalog function of the Bootstrapper class becomes an entry point to the module. This class has to implement the IModule interfaces. When the Prism loads a module, it calls the Initialize method of this interface. This is where the module has a chance to declare its intentions and register all the views, models, presenters, services, etc.

    The CustomerManager.ListView module loads a CustomerListViewModel during the initialization, which, in turn, initializes a CustomerListView WPF user control as its view, and then inserts it into a CustomerListView region that, as we have seen above, was declared by the shell window:

    var viewModel = _container.Resolve<CustomerListViewModel>();
    
    IRegion region = 
           _regionManager.Regions[RegionNameConstants.CustomerListView];
    region.Add(viewModel.View);
    region.Activate(viewModel.View);
    

    This pattern is pretty well documented and you can read more information about development of Composite applications from the MSDN Magazine article, “Patterns For Building Composite Applications With WPF,” by Glen Block (msdn.microsoft.com/en-us/magazine/cc785479).

    The third CustomerManager.Services module is a little different from the first two in that it is a services-only module. This module does not register any models or views, but simply registers a single service – CustomerDataService. The reason that this service is in a separate module allows us, as we will see later, to easily replace one functionality with another.

    Note that we have left the host application empty. Apart from loading the Bootstrapper and creating a Shell window, it does nothing. In reality, it is not necessary, but will help to prove our point – if you follow the composite application guidelines the hosting of your application does not matter and can change easily via configuration at any moment of the development process depending on the current project needs.

    You can see how our application looks in Figure 1.

    clip_image002

    Figure 1: CRM Customer Management application

    Now we have a real, but simplified, CRM application that allows users to select a customer from the list and see the customer’s information in a separate view. Per our design, the three modules are loosely coupled and can be easily rearranged and hosted in other applications.

    Let us see what we can do with this design and architecture.

    Configuration-driven application composition

    As we know from experience, to increase the flexibility for the application it is beneficial to use configuration files. This even reduces the code complexity and component dependencies. You have to follow a simple set of steps:

    1. Create an App.config file
    2. Include a module configuration section
    3. Replace the ModuleCatalog with ConfigurationModuleCatalog in the ConfigureModules method of our bootstrapper.
    4. Make sure that app.config file is deployed in the same folder as the executable. Note that the best way to avoid deployment conflicts is to make sure that your config file has a unique name and does not collide (or overwrite in the worst case) with a configuration file from another AddIn or application that was deployed in the same folder.

    On application startup, the bootstrapper will allow the Prism framework to locate the required configuration file and load all the required modules. Note that the way the location of the configuration section is implemented, the very first configuration section will be loaded from the first *.config file that is loaded. Be warned, but continue reading – later we will discuss how this can be addressed.

    Integrating with Word

    So far, we have seen how to build a usual WPF composite application using the Prism guidelines. There is plenty of information about this on the internet, but what we are going to do next is different.

    Let us see how we can integrate our CRM Customer Manager into an Office application. We will use Word as our first target.

    This is what we would like to achieve: when our sales managers start Word, we are going to show them a customer list and, when they select a customer from it, the name will be automatically inserted into the currently open document. In real life, this could be a sales order. Also, when a customer’s name appears in a document, it will be recognized by the CRM application and will allow the sales manager to find the available customer info that is currently in the CRM database. Our application will use SmartTags for the customer name recognition and will provide a link between the recognized names and the CRM application.

    We are going to use VSTO and Visual Studio Office AddIn templates as a starting point. These templates provide you with a basic Visual Studio solution and an empty AddIn skeleton. Make sure to create an appropriate AddIn for a targeted Office application – each different application requires a different AddIn.

    We have to initialize and run an application bootstrapper from the ThisAddIn_Startup method since it is a starting point for the AddIn. If we run the bootstrapper that we have created for our reference application without any changes, a standalone WPF window will pop up and will live separately from our hosting office application. This is not really what we want. We would like to see our Customer List, as well as the Customer info on the side custom task pane. This means that we have to create a custom task pane, and host our WPF shell window in it.

    In a normal WPF application, the role of the shell window can play any WPF content control, i.e. window, panel, or another control, whereas in Office applications there are no WPF “islands”. The usual way to put a WPF control on a Custom Task pane is to insert a WinForms User control that hosts a desired WPF control in a WPF Element Host. All this should be done in the AddIn startup or in a composite application bootstrapper.

    ü Performance optimization tip – in order to slightly improve user experience while loading your AddIn, you should postpone loading all the components until the office host application is fully loaded and stable.

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        System.Windows.Forms.Application.Idle += OnIdle; 
    }
    
    private void OnIdle(object sender, EventArgs e)
    {
        System.Windows.Forms.Application.Idle -= OnIdle;
    
        _bootstrapper = new ApplicationBootstrapper(...);
        _bootstrapper.Run();
    }
    

    Creating Multi-shell/multi-window composite WPF applications.

    Now we have a full and seamless integration with Word. However, there is a catch! This is not an entirely correct solution! The current implementation will work only for a first opened document instance. During the AddIn initialization, one and only one instance of a custom pane will be attached to the very first document instance. However, since most of the Office suite applications are multi-document – the other windows opened by our sales managers will not have the attached custom task panes.

    Office applications bring a special challenge for composite applications. The architecture of an Office application is all about a multi-document environment. Each document represent a self-sustaining instance, but, since the environment a priori allows cross document communication, nothing stops an application developer from coming up with clever applications that thrive on this feature and bring interesting solutions to the table.

    In order to overcome this challenge the AddIn should track all the instances of the document windows, create new panes (with shell window), and attach them when a new window is created and destroy them when the document windows is closed. This is a complicated issue. However, we are lucky – there is a published solution for this case. For more information about tracking Word windows read the MSDN article, “Managing Task Panes in Multiple Word and InfoPath Documents” (msdn.microsoft.com/en-us/library/bb264456).

    So far, we have tracked all the places we had to create a shell window, but we cannot do it blindly. According to Prism guidelines, we are allowed to create only one Shell window!

    Rest assured that this is not a hard limitation. Thanks to the Prism team for making an incredible effort and releasing the source code, it was possible to find a solution by adding a small extension to the guidelines.

    Let me introduce the concept of a Multi-window or Multi-shell composite application.

    To simplify the explanation of the process, let’s go back to our original WPF reference application.

    Compare the original Diagram 2 with the Diagram 3 where you can see the location of the different prism services and application modules.

    clip_image004[8]

    Diagram 3: Multi-window composite CRM application architecture

    Note that we want to leave the DB service to be common to all of the shell windows – it will have only one instance. This simplifies the design and reduces amount of the connections that have to be established to the database.

    Thanks to the use of Unity IoC Container, we can achieve such architecture via the creation of the container hierarchies. The root container will hold a reference to our DB process, and the nested (children) containers will hold references to their own region managers and shell windows.

    Our application creates a main (root) Unity container that becomes a root (or parent) for the others, and registers the DB service. Each time a new document window is created, it creates a separate container that becomes a child to the root , and initializes a new bootstrapper within the new container. When the composite application tries to resolve the application services, the references will come from the child containers, but, when it needs the DB service, Unity will always resolve it to that single instance that was registered within the root scope. This is a feature of nested containers – if a required type or instance cannot be found in the current container, Unity will check its parent, then parent of a parent, and so on and so forth.

    ü Our CRM composite application will need two bootstrappers – one for the application level scope and one for the document level scope.

    Our CRM composite application will create a new document-scoped bootstrapper instance in each nested Unity container instance. Each nested bootstrapper is going to set its Container property to a child instance of an application-scope Unity container. The document-scoped bootstrapper will initialize all the Prism-related services in the nested Unity container, even if they are already present in the application-scope Unity container.

    Understanding this concept is crucial for understanding how multi-document composite applications operate.

    As you can guess, each shell should have its own instance of all of the crucial services, like RegionManager, RegionMappings, etc. Since we’re not planning to change the standard way that modules with regions are initialized, the modules have no way to specify into to what shell instance they are going to inject visual elements – we need to have a separate per-shell ModuleInitializer service.

    The Unity IoC nested container feature provides us with beautiful scope isolation and hierarchical type resolution. By having the ModuleLoader service present in all scopes (root and nested) we ensure that the modules it loads are properly isolated from other instances of the same modules by scope boundaries. This allows us to have services shared between the scopes, as in our case where we share the CRM Customer DB storage between all the scopes. The fact that we have an EventAggregator in the root scope allows event delivery on the application level scope and between the nested scopes. Be aware that although we have EventAggregators in each scope as well, they do hide the root instance and provide in-scope event delivery. Therefore, if we need to make sure that events will be broadcasted between the scopes, an extra event bridge is required. If such a bridge is needed, it can be achieved by creating an event handler that subscribes to a required event in one scope and publishes the same event type, or another one, in the destination scope. Do not forget that event filters still apply and can provide extra help in choosing an appropriate event route.

    Now that we understand the principals of multi-window composite applications, let us see how one is implemented. I am referring to the CustomerManager.MultiWindowApp in the attached sample code.

    Following the Prism guidelines, the OnStartup method of the App.xaml initializes the ApplicationBootloader and runs it:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
    
        var bs = new AppBootstrapper();
        bs.Run();
    }
    

    The root scope ApplicationBootstrapper is inherited from the MinimalUnityBootstrapper. The MinimalUnityBootstrapper, on its own, inherited from the usual UnityBootstrapper and does the minimal set of the required initializations to the Unity container by registering only ServiceLocator, ModuleInitializer, ModuleManager and EventAggregator services. The rest of the services that the standard UnityBootstrapper loads are omitted since the multi-window composite application is not going to need them in the root scope. The MinimalUnityBootstrapper hides the default Run() method and makes sure that by default the ConfigureContainer will not force the registration of the omitted services.

    When the Run() method of the ApplicationBootstrapper is called by the Application class, it creates an instance of a shell window bootstrapper – one per each window it decides to open:

    public override void Run()
    {
        base.Run();
    
        // Creates a first window
        bs1 = new Bootstrapper { ParentContainer = Container };
        bs1.Run();
    
        // Creates a second window
        bs2 = new Bootstrapper { ParentContainer = Container };
        bs2.Run();
    }
    

    Note that while initializing the shell window bootstrappers, the ApplicationBootstrapper passes its Unity container as a ParentContainer. This is a required step to create nested container scopes.

    From the fact that the shell window bootstrapper is inherited from the NestedScopeUnityBootstrapper, it follows the standard bootstrapper implementation pattern as it described in the Prism guidelines.

    All the “magic” is hidden by the NestedScopeUnityBootstrapper in the CreateContainer and the ConfigureContainer methods. In the CreateContainer, the NestedScopeUnityBootstrapper creates a child container for the ParentContainer, which was provided to it by the ApplicationBootstrapper:

    protected override IUnityContainer CreateContainer()
    {
        ...
        return ParentContainer.CreateChildContainer();
    }
    

    When ConfigureContainer is called, the NestedScopeUnityBootstrapper has to force the registration of all the required services for the composite WPF application due to the simple fact that the original UnityContainer skips the registration of these services if they already have been registered somewhere in the hierarchy of the Unity container. By forcing the registration of all the services the NestedScopeUnityBootstrapper ensures that the newly created scope will have its own, totally isolated, set of the required services.

    On a side note: the NestedScopeUnityBootstrapper allows you to decide whether you would like to have a single instance of the EventAggregator for the whole application, or to have an instance per each scope.

    ü A fun fact: guess what will happen if the eventAggregator is common to all the scopes?

    ü Answer: the shell windows will all display the same customer info after a customer name is selected in one of them.

    Multi-shell Configuration driven deployment

    From our earlier discussion about the use of the configuration files, we know that we can compose our application this way, but, since we have altered the basic paradigm, it will not work out of the box.

    When a UnityBootstrapper is told to look for module dependencies in a config file, by creating a ConfigutationModuleCatalog instance in the GetModuleCatalog method of your bootstrapper, it will start looking for the very first *.config file it can find in the folder that the current application domain was initialized from. It will load the first “modules” configuration section it finds in this file. Then it will load all the modules specified in that section.

    The described above logic is not going to work in the case of multi-window composite applications since such an application will have more than one shell running. As we already know, this means that such an application will have multiple scopes. Each scope, as we have seen earlier, has its own configuration and has to have its own set of loaded modules.

    To overcome this limitation we are going to change the configuration loading logic. There are a multiple ways to do this and I am going to show you the simplest. We are going to leave the current ConfigurationModuleCatalog implementation intact, after all, it does what it has to do, but we are going to change how it discovers the required configuration sections.

    We define our own ConfigurationStore logic by creating a new FilteredConfigurationStore class, and substitute it place of the default one for the ConfigurationModuleCatalog:

    protected override IModuleCatalog GetModuleCatalog()
    {
        var catalog = new ConfigurationModuleCatalog();
        catalog.Store = new FilteredConfigurationStore("modulesRoot");
        return catalog;
    }
    

    Note that the FilteredConfigurationStore is initialized with a section name. This allows us to create multiple module configuration sections in the config file and thereby initialize different scopes with different configuration sections. This is how the modified App.config file looks:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="modulesRoot" 
      type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection,
            Microsoft.Practices.Composite.Desktop"/>
        <section name="modulesScope" 
      type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection,
            Microsoft.Practices.Composite.Desktop"/>
      </configSections>
      <modulesRoot>
        <module assemblyFile="CustomerManager.Services.dll"
           moduleType="CustomerManager.Services.ServicesModule, 
           CustomerManager.Services" moduleName="ServicesModule" />
      </modulesRoot>
      <modulesScope>
        <module assemblyFile="CustomerManager.ListViewModule.dll" 
           moduleType="CustomerManager.ListViewModule.ListViewModule,
           CustomerManager.ListViewModule" moduleName="ListViewModule" />
        <module assemblyFile="CustomerManager.InfoViewModule.dll" 
           moduleType="CustomerManager.InfoViewModule.InfoViewModule, 
           CustomerManager.InfoViewModule" moduleName="InfoViewModule" />
      </modulesScope>
    </configuration>
    

    The “modulesRoot” section is used to initialize application root scope, and the “modulesScope” section is for child scope initialization.

    Applying Multi-shell paradigm to the Office WPF composite applications

    So far, we have seen how the principals of the multi-shell composite applications work in usual WPF applications. Let us see how to apply all this knowledge to the applications integrated into the Microsoft Office suite. Let us get back to our Word AddIn and will make sure that it works correctly in the multi-window environment.

    Let us name the root-level scope an Application Scope, and the nested ones, since they are created for each document instance/window, the Document Scopes. Each document scope is initialized when the application detects the presence of a new document window.

    Note that the ApplicationBootstrapper, representing an Application Scope, is inherited from WordApplicationBootstrapper which makes sure to register with Unity all the Word-related global containers like Custom Task Pane collection, Ribbon collection, Smart Tags collection and, of cause, the reference to the Office application itself. All these registrations are done in the parent Unity container. This ensures that all these instances will be available in all the nested scopes.

    One of the critical things the WordApplicationBootstrapper takes care of is the initialization of a DocumentManager. The DocumentManager manager tracks all the document windows in the system and each time there is a new one, or an old one is closed, it calls back to a service that implements the IWindowManagerShell interface. When the WordApplicationBootstrapper, since it has registered itself to receive these callbacks, receives a notification about creation of a new window, it forwards this request to its inheritor, the ApplicationBootstrapper, via OnNewWindowOpenned method. When this method is called, the ApplicationBootstrapper creates a Document Scope bootstrapper that creates and initializes a shell window. This shell window is returned back to the DocumentManager, which makes sure that a new Custom Task pane is created to host it. As soon as WPF starts rendering a shell window – the local in-scope RegionManager will take care of initializing all of the regions and region mappings. Then the standard composite application logic does the rest – modules are loaded and initialized and the appropriate views are put in place in their appropriate regions.

    So far, we have received an integration of all the visuals of our CRM application with one of the Office Suite applications – Word. This is a great progress on its own and can be used to a certain degree, but not used to its full potential. Let us see how we can achieve a bi-directional integration with Word.

    One of the requirements was when a customer is selected his or her name is inserted into the document. To get a customer selection event, the Document Scope (since all these actions should be done per each document) bootstrappers, in the CreateWindowShell method, subscribes OnCustomerSelected callback to a CustomerSelectedEvent via an in-scope EventAggregator service. When this event is published, the EventAggregator calls the registered callback. This will cause a customer name to be inserted into the associated document:

    private void OnCustomerSelected(CustomerItem customer)
    {
        ...
        WordUtilities.TypeText(CurrentDocument, customer.Name + " ");
    }
    

    Another requirement was to make sure, when a customer name is selected – his or her information will be shown in the CustomerView region.

    To achieve this goal we are going to use the built-in to Word hot word recognition feature – Smart Tags.

    Since we are going to use SmartTags, make sure that they are enabled in Word. For more information about enabling SmartTags see the MSDN article, “How to: Enable Smart Tags in Word and Excel” (msdn.microsoft.com/en-us/library/cc442764).

    To make sure the Smart Tag functionality knows about our names, we add a list of all the Customer’s names to the SmartTag collection as soon as the Document is initialized from the Document-scope bootstrapper:

    WordUtilities.AddSmartTags(from customer in _cusomersService.GetCustomers() select customer.Name, smartTags, CurrentDocument, OnSmartTagClick);
    

    Note that the list of names is extracted from the _customerService. It is a reference to the global instance of the ICustomerDataService that was registered in the Application-scope bootstrapper.

    The AddSmartTag utility method creates a document-scope SmartTag, which will associate customer names as terms. The action Click of this SmartTag is associated with the OnSmartTagClick callback:

    void OnSmartTagClick(object sender, VSTO.ActionEventArgs e)
    {
        var customer = _cusomersService.GetCustomerByName(e.Text);
    
        ...
        _eventAggregator.GetEvent<CustomerSelectedEvent>()
           .Publish(activeCustomer);
    }
    

    Note that when the SmartTag calls the OnSmartTagClick, the callback will find a reference to a recognized customer in the CRM database, via the _customerService and will notify all the subscribers in the scope about this selection. You can see how Word recognizes a customer last name as a SmartTag on the Figure 2.

    clip_image006

    Figure 2: Customer Management integrated into Word

    Predicate event filtering

    One of the great features of the EventAggregator is – predicate-based event filtering. This is a very powerful feature and allows very granular event subscription. In our case, we’re using this feature for “echo canceling”. Exactly the same CustomerSelectedEvent event is published (broadcasted) when a sales manager selects a customer from the customer list and when he chooses an action on a SmartTag. When this event reaches the CustomerListViewModel, it does not really know whether to update a customer selection in the list or not, since it is not sure what was the cause of the event. So, in order to remove the “echo”, we make sure to ignore such an event when it references an already selected customer.

    eventAggregator.GetEvent<CustomerSelectedEvent>().Subscribe(
        customer => SelectedCustomer = customer, ThreadOption.BackgroundThread, 
        false, customer => customer != _selectedCustomer);
    

    Note that the last portion of this subscription is the predicate. It tells the system to execute the specified action (SelectedCustomer = customer), only if the customer referenced in the event is not currently selected (customer != _selectedCustomer).

    Integrating the CRM application with Outlook

    The techniques and paradigms we have learned while integrating with Word apply to the rest of the applications in the Microsoft Office suite. Here I am going to show you an example of how you can integrate the CRM application with Outlook.

    Note that the AddIn and the Application-scope bootstrappers are identical to those we have created for Word AddIn, except one small detail – the Application-scope bootstrapper is inherited from the OutlookApplicationBootstrapper. This is done for a reason – the OutlookApplicationBootstrapper registers a different, Outlook-oriented window manager, the OutlookWindowManagerService. This service does a similar job in tracking all the Outlook window instances.

    Custom Task panes in the Outlook are associated with a specific Explorer or Inspector window. Explorers are the windows that display the contents of a folder whereas Inspectors display contents of an item such as an e-mail or a contact. When a new Explorer or Inspector window is opened, a new instance of a Custom Task pane should be created and associated with it. For simplicity, we are going to concentrate on the Explorers only, so our shell window will be associated with every one of them. (For more information on tracking Outlook windows see the MSDN article, “Walkthrough: Displaying Custom Task Panes with E-Mail Messages in Outlook” (msdn.microsoft.com/en-us/library/bb296010).

    When a new Explorer window is created, a Window-scoped bootstrapper is initialized. This is where we are going to hook up all our Explorer-scoped functionality.

    Let us see, for example, how we can kick off an e-mail search when a customer is selected in the ListView region of our CRM application.

    First, as we’ve seen earlier, we need to subscribe to a CustomerSelectedEvent with the window-scoped EventAggregator and, when this event is published, we’re going to start a simple search of all e-mails where “From” field contains customer name:

    private void OnCustomerSelected(CustomerItem customer)
    {
        CurrentWindow.Search("from:" + customer.Name,
          OlSearchScope.olSearchScopeCurrentFolder);
    }
    

    The result you can see on Figure 3:

    clip_image008

    Figure 3: Customer Manager kicks off a search when a customer is selected

    Conversely, we can make sure that when an e-mail from a customer in our CRM database is selected, the appropriate customer info is displayed in the CustomerInfoView. This is done by subscribing to a SelectionChange event of the current explorer window:

    CurrentWindow.SelectionChange += OnItemSelectionChange;
    ...
    void OnItemSelectionChange()
    {
        var selection = CurrentWindow.Selection;
        ...
        if (selection[1] is MailItem)
        {
            var mailItem = (MailItem)selection[1];
    
            var customer = _cusomersService
                       .GetCustomerByFullName(mailItem.SenderName);
    
            if ((customer != null) && (customer != _selectedCustomer))
            {
                _selectedCustomer = customer;
                _eventAggregator.GetEvent<CustomerSelectedEvent>()
                       .Publish(_selectedCustomer);
            }
        }
    }
    

    When the SelectionChanged event is called, the Bootstrapper makes sure to extract a full name of a sender, get a reference to a customer information, and, if the customer was found in the CRM database, publishes a CustomerSelectedEvent via EventAggregator.

    Note that the code makes sure that it works only with Mail items. This is not a limitation and is done only to simplify the example.

    Revealing the hidden gems of the composite applications

    If after reading this article and getting to this point you are still unclear how is this way better than the old method, and you still want to ask a question: “I can do this the usual way and get the same results”, then you have come to the right place. This section is for non-believers like you.

    Now ask yourself a question: “how hard it is in a normal monolithic application to replace the current DB service with the one that, instead of reading customer info from a private DB, will get these contacts from an Outlook Contacts folder?” The answer is very simple for a composite application: implement a new service and change the application configuration. No need to recompile the AddIn or other services, no need to refactor – you do not touch your existing code at all. The deployment procedure is trivial – drop a new module in the deployment folder and change the application configuration. Prism and the Unity application blocks will take care of the rest.

    Let us see how it is done. In the sample code, a new Class Library is created based on the code of the CustomerManager.Services class library. Then the class CustomerDataService is changed to work with Outlook instead of the CRM database.

    In the constructor, the CustomerDataService gets a reference to the Outlook application. Then this reference is used, for simplicity of this explanation, to get to the default Contacts folder and to cache all the found contacts, including their contact pictures.

    public List<CustomerItem> GetCustomers()
    {
        if (_customers == null)
        {
            var contactFolder = _application.Session.GetDefaultFolder(
                    Outlook.OlDefaultFolders.olFolderContacts);
    
            Outlook.Items contacts = contactFolder.Items;
    
            _customers = new List<CustomerItem>();
    
            foreach (Outlook.ContactItem contact in contacts)
            {
                if (! string.IsNullOrEmpty(contact.FullName))
                    _customers.Add(new CustomerItem { 
                         Name = contact.FullName, 
                         eMail = contact.Email1Address, 
                         Picture = ContactHelperUtilities.GetImage(contact) });
            }
    
            _customers.Sort((contact1, contact2) => 
                contact1.Name.CompareTo(contact2.Name));
        }
    
        return _customers;
    }
    

    The last thing to do is to replace the old CustomerDataService with the new one. This is why the old line in the App.config file:

    <module assemblyFile="CustomerManager.Services.dll" 
        moduleType="CustomerManager.Services.ServicesModule,
        CustomerManager.Services" moduleName="ServicesModule"/>
    

    is replaced with the new one:

    <module assemblyFile="CustomerManager.OutlookServices.dll" 
        moduleType="CustomerManager.OutlookServices.ServicesModule,
        CustomerManager.OutlookServices" moduleName="ServicesModule"/>
    

    Note that the assemblyFile and the moduleType attributes have changed.

    Immediately start Outlook again, and you will see a different result, like the one you can see on Figure 4.

    clip_image010

    Figure 4: Customer Manager reads Customer Info from Contacts folder

    Wrapping Up

    Prism (Composite Application Guidance for WPF and Silverlight) does not solve all your problems out of the box, but certainly guides you towards a path of creating loosely coupled but cohesive GUI applications. Along with the Unity application block, they become a great addition to your developer’s toolbox. In the beginning, it is a bit challenging to wrap your head around it because it brings new paradigms to the development processes we are used to, but have a little patience and give it a try. You will see that the new way of thinking is not that different from what you have always been doing. Following common guidelines across the different projects and development teams makes not only utility libraries, but also the graphical components easily interchangeable. And, as you have seen from the article, you can change your mind about their layouts and how they are hosted at any point of your development cycle as well as during the installation at a customer site.

    I would like to dedicate this article to my family, my dear wife Ira and amazing daughter Dana, and to Hank Schwartz and Mike Jenks , dear friends, all who have supported me during this amazing adventure. Wish you all the best.

    Resources and Useful links

    Patterns & practices – Unity – www.codeplex.com/unity

    Unity Application Block – msdn.microsoft.com/en-us/library/dd203104

    Patterns & practices: Composite WPF and Silverlight – www.codeplex.com/CompositeWPF

    Composite Application Guidance for WPF – msdn.microsoft.com/en-us/library/cc707819

    Source Code – download

    About these ads

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s

     
    Follow

    Get every new post delivered to your Inbox.

    %d bloggers like this: