Click to Rate and Give Feedback
MSDN
MSDN Library

  Switch on low bandwidth view
Overview of the Composite UI Application Block
 

Patterns and Practices home

The Smart Client Software Factory helps architects and developers create composite smart client applications. A composite smart client application is composed of a number of discrete, independent, yet functional pieces. These pieces are integrated together within a host environment (such as a Windows Forms application) to form a fully coherent smart client solution.

Not all smart client applications are composite smart clients. A Windows-based application can provide a rich user experience, be responsive, use local resources, and exchange data on the Internet or an enterprise network without being composed of discrete pieces integrated functionally and visually into a Windows-based application. Developers successfully use Visual Studio and Windows Forms to create such applications.

The Smart Client Software Factory is designed to address requests from architects and developers who create smart client applications and need to:

  • Build clients composed of independent yet cooperating modules.
  • Separate the concerns of module builders from the concerns of the shell developer, allowing business units to concentrate on development of domain-specific modules instead of the client architecture.
  • Use an architectural framework for producing a consistent and high quality integrated desktop development.
  • Increase productivity and reduce overall development time through consolidating architect and developer efforts.

Because the Composite UI Application Block is designed to address these application needs, the applications you create with the Smart Client Software Factory use the Composite UI Application Block. To fully understand the guidance in the Smart Client Software Factory, you must be familiar with this application block.

Note This topic provides an introduction to the key concepts of the Composite UI Application Block. The Composite UI Application Block has been developed as a result of analyzing common enterprise development challenges and successful solutions to these challenges. However, because each application is unique, you will have to analyze whether this application block is suitable for your particular needs. To evaluate this application block and determine its applicability to your projects, it is suggested that you dedicate at least half of a day to explore the application block. To explore the application block in depth, see the Smart Client – Composite UI Application Block in the Microsoft patterns & practices Developer Center and Composite UI Application Block Community in the GotDotNet patterns & practices Code Gallery.

Benefits

The following sections describe how the Composite UI Application Block benefits both architects and developers.

Separation of Concerns

Developers can use the Composite UI Application Block to develop smart client applications composed of independent, but collaborating, modules. Productivity increases because each developer (or team) is able to concentrate on a specific task. For example, developers of service components work with only the business logic in the component; they do not have to be concerned with background issues, such as threading and security or the appearance and behavior of the application.

Applications built with the Composite UI Application Block have a design that delineates the difference between writing shell logic (requiring expertise in Windows Forms, user controls, and appearance and behavior), infrastructure components (built only once per application or re-used from other applications), and business logic (the user interfaces, logic, entities, and service agents of the specific application). This means that the application architecture supports developers and teams that have different concerns during the creation of an application. Figure 1 illustrates an example of a Composite UI Application Block application architecture that supports concerns of different teams and individuals with different expertise within a team.

Click here for larger image

Figure 1. Separation of concerns with a Composite UI Application Block application

Modularity

The Composite UI Application Block promotes modularity by allowing you to implement business logic, visual components, infrastructure components, presenter or controller components, and any other objects the application requires, in separate modules. Developers can easily create visual parts and implement business logic independently of the application shell. The Composite UI Application Block design separates the concerns of the following developers participating in a smart client solution:

  • Smart client shell and visual parts developers who are responsible for the user interface design and implementation
  • Business logic developers who are responsible for implementing use case logic
  • Infrastructure developers who are responsible for providing common services such as logging, security, and so on

Extensibility

The Composite UI Application Block provides a generic shell architecture, so its design promotes extensibility in many different ways. With it, you can do the following:

  • Replace the behaviors and strategies provided as defaults (such as the way in which modules are loaded and the way that state is saved) with your own implementations.
  • Add custom services and behaviors as required by your applications.

Overview

This section provides an introduction to some key concepts of the Composite UI Application Block.

Patterns

The application block provides support for implementing many useful patterns for smart client development. Figure 2 depicts common patterns used in Composite UI Application Block applications.

Aa546409.02-scsf-cabpatterns(en-us,MSDN.10).png

Figure 2. Patterns implemented, or supported, by the Composite UI Application Block

Flow of Components

The Composite UI Application Block supports a containment model for components, such as services, event topics, commands, work spaces, and UI extension elements. A container determines the visibility and life cycle of its components. Component instances that are closely related are typically in the same container, and therefore, they are created together and disposed of together.

Note In a Composite UI Application Block application, a WorkItem is a container.

A component can access any other component that is in the same container. Components flow from a parent container to a child container. This means that the components in a child container can access components in its parent container. For example, the root of a Composite UI Application Block application is the shell. The shell typically contains workspaces, UI Extension Sites, commands, and services. Because the shell is the root of the application, these components are available to any child container.

In Figure 3, use case A creates additional components. These additional components can access the components in the same container and also the components in the shell container. Similarly, if use case A creates use case B, use the components in use case B's container can access the shell's components and use case A's components.

Aa546409.02-scsf-cabpushdown(en-us,MSDN.10).png

Figure 3. Flow of components

User Interface Integration Example

With the Composite UI Application Block, developers can compose smart client solutions from a number of discrete parts that are hosted within a shell environment. The shell developer can define a general layout to host user interface elements. User interface component developers can create components that are hosted in the shell. The mechanism of communication between the discrete parts of an application and the shell is through the root WorkItem.

Every Composite UI Application Block application contains a root WorkItem. The root WorkItem is a container for components that are shared across the application. These shared components include visual parts that can be extended by modules. For example, the shell application can expose a MenuStrip as a UI extension site (a UI extension site is a Composite UI Application Block user interface element that is designed to be extended by different components in an application). Figure 4 illustrates a Composite UI Application Block application that exposes a StatusStrip and MenuStrip as UI Extension Sites.

Aa546409.02-scsf-cabwalkthrough1(en-us,MSDN.10).png

Figure 4. Shell application with root WorkItem and UI Extension Sites

The Composite UI Application Block supports the customization of an application using solution profiles in a catalog. A solution profile is a list of modules that should be loaded into an application. When the application starts up, the Composite UI Application Block reads the catalog and loads the specified modules.

After a module is loaded, it can add elements to the shell's UI Extension Sites. For example, a module can add menu items to the shell's MenuStrip to expose the module's features. If the entry for that module is removed from the catalog, the module will not be loaded when the application starts. The application will continue to function, but the menu items for that module will not appear. Figure 5 illustrates a module that adds menu items to the shell MenuStrip.

Aa546409.02-scsf-cabwalkthrough2(en-us,MSDN.10).png

Figure 5. Menu items added by module

Modules can also contain visual representations of data, such as a control, a Windows Form, or a wizard page. These visual representations are referred to as views or SmartParts. As an example, a module that manages information from a Customer Relationship Management (CRM) system has a view that displays a customer's contact information. The module loads this view during module initialization. When the application executes the business logic that requires the customer contact information to be displayed, the application loads the customer contact information view into the shell. Figure 6 illustrates a module that adds two views to the root WorkItem and later displays the views in the shell.

Aa546409.02-scsf-cabwalkthrough3(en-us,MSDN.10).png

Figure 6. Views defined in module displayed in shell workspaces

WorkItems encapsulate object collaborations for a specific use case, typically using the Model-View-Controller (MVC) pattern. The WorkItem supports the MVC pattern through the following:

  • Model. This is represented by a WorkItem state.
  • View. WorkItems may contain one or more views.
  • Controller. Each view has associated controllers that expose object interfaces for tightly bound interactions and loosely coupled interfaces in the form of commands, events, and subscriptions.
Note The Smart Client Software Factory also includes support for the Model-View-Presenter (MVP) pattern.

Figure 7 illustrates a module with a WorkItem that contains a view. The module adds this WorkItem to the root WorkItem (it is a child of the root WorkItem). When the application executes the WorkItem, the WorkItem loads its view into the shell.

Aa546409.02-scsf-cabwalkthrough4(en-us,MSDN.10).png

Figure 7. View in module WorkItem displayed in shell workspace

Developing Applications

This section introduces developers to the main components of the Composite UI Application Block.

Consolidating User Interface and Shell Expertise

With the Composite UI Application Block, developers with shell expertise can build components that hide user interface complexity from the business logic development. The Composite UI Application Block provides an architecture around these components and an implementation based on Windows Forms. It includes:

  • A consistent way of showing and hiding SmartParts (controls) using Workspaces. A shell developer can consistently introduce visual effects, layout strategies, or other behaviors without affecting the business logic components.
  • A common way of adding and using UIElements into the shell, such as menu items, status bars, so that the developer of an individual piece of business logic does not need to know how or where that element will be shown.
  • A Command architecture that allows a business logic developer to separately define actions a user can take and how they are displayed in a specific shell.

SmartParts and Workspaces

SmartParts are the visual components of an application. You can create SmartParts by customizing a standard user control. There are two scenarios for using SmartParts in a Composite UI Application Block application:

  • The SmartPart required for a specific location on a form is known at design time.
  • The SmartPart is created and displayed dynamically at run time, typically in response to user interaction.

If you know the location at design time, you can drag the SmartPart into a suitable workspace to achieve the required layout of the form contents. For example, you can use a TabWorkspace or a ZoneWorkspace.

To dynamically display a SmartPart at run time, you can either allow a workspace control to manage the positioning and dimensions of the SmartPart (for example, in a TabWorkspace) or you can explicitly designate an area in a form where the SmartPart will appear at run time by using a SmartPartPlaceHolder control. You use the Show method of a workspace to display a SmartPart in a workspace. For example, the following code creates an OfficerPanelView SmartPart and shows it in the workspace identified by the string "OfficerPanel."

OfficerPanelView view = WorkItem.SmartParts.AddNew<OfficerPanelView>();
WorkItem.Workspaces[“OfficerPanel”].Show(view);

Workspaces are components that encapsulate a particular visual way of displaying controls and SmartParts. The Composite UI Application Block includes the following types of workspaces:

  • WindowWorkspace. This workspace enables you to show and hide controls framed in a window.
  • MdiWorkspace. This workspace enables you to show and hide controls and SmartParts in MDI child forms.
  • TabWorkspace. This workspace enables you to show and hide controls and SmartParts inside a tabbed page.
  • DeckWorkspace. This workspace enables you to show and hide controls and SmartParts in an overlapped manner with no visible frame.
  • ZoneWorkspace. This workspace enables you to create a tiled workspace layout.

Showing controls through workspaces allows you to consistently display, hide, activate, and monitor the parts shown, independently of the visual style in which they display. This allows the appearance and behavior and the layout of your shell to evolve independently of the SmartParts hosted within it.

UI Elements

The Composite UI Application Block enables you to create common user interface elements in a shell that components in a module can access. For example, you can create add menu items to a menu bar. Developers register a user interface element as a UI extension site. (The UI extension site is identified by a string.)

RootWorkItem.UIExtensionSites.RegisterSite(“FileMenu”, Shell.MainMenuStrip);

The application block provides a UI extension site catalog (collection) for each WorkItem. This catalog allows you to access and manage the elements in the catalog using the site name of the element.

ToolStripMenuItem printItem = new ToolStripMenuItem("Print");

RootWorkItem.UIExtensionSites[“FileMenu”].Add(printItem);

Commands

Frequently, applications contain more than one control that invokes the same method. For example, a menu item and tool bar item may both run the OpenFile method. The Composite UI Application Block uses the concept of commands to enable you to write one event handler that is associated with more than one user interface element, and associate one user interface element with multiple command handlers.

Achieving Modular Design of Your Business Logic

The functionality that focuses on helping you achieve loose coupling between your modules includes:

  • WorkItems that provide an easy way to scope which collaborating components participate in a use case, share state, events, and common services.
  • An Event Broker that provides a many-to-many, loosely coupled event system mechanism between objects in your application.

WorkItems

A WorkItem is a run-time container for components. The components can be both visual and non-visual parts of the application, such as SmartParts, controls, and services.

A service is a supporting class that provides functionality to other components in a loosely coupled way. The Composite UI Application Block includes a set of basic services that you can use in your applications. You can also build your own services that provide infrastructure capabilities specific to your applications. For example, the Bank Branch Client includes the service CustomerFinderService, which exposes the capabilities of a Web service that looks up customers in a back-end system.

A WorkItem exposes a Services property that you can use to add a service to the WorkItem. The following code shows how to add the CustomerFinderService to a WorkItem.

WorkItem.Services.AddNew<CustomerFinderService, ICustomerFinderService>(); 

A component within a WorkItem can ask the WorkItem for any other component. The following code shows how you can request the service that implements the ICustomerFinderServcie interface.

ICustomerFinderService customerFinderServcie = 
         WorkItem.Services.Get<ICustomerFinderService>();

There is always an active WorkItem, and you can activate and deactivate WorkItems as required. For example, a user may be in the process of entering a customer order when he or she needs to update that customer's details. The application can support the deactivation of the order WorkItem and activate the customer details WorkItem.

Every Composite UI Application Block application has a single root WorkItem. The Composite UI Application Block creates the root WorkItem when the application starts. As an application executes, it creates additional WorkItems to implement application use cases. The application adds these additional WorkItems to a parent WorkItem (for example, to the root WorkItem) .You can think of a Composite UI Application Block smart client application as a WorkItem hierarchy, with the root of the hierarchy being the root WorkItem. Figure 8 illustrates an example WorkItem hierarchy. In this figure, the application creates a WorkItem for a use case and adds it to the root WorkItem. The WorkItem for the first use case creates two instances of the second WorkItem to implement two instances of the second use case.

Aa546409.02-scsf-cabworkitemcontainers(en-us,MSDN.10).png

Figure 8. WorkItem hierarchy

Note You can use a WorkItem to encapsulate different use cases or areas of an application to share events and state. However, if you overuse WorkItems and make them too fine grained, or if you build your WorkItem classes inconsistently, you may end up with an application that is difficult to maintain.

Events

Components can use events to publish or receive notifications. The Composite UI Application Block contains an event broker system that enables you to implement a multicast event scheme (that is, a scheme where zero or more event publications work with zero or more event subscriptions).

You publish an event by adding the EventPublication attribute to an event declaration, as shown in the following code. The topic name is a string and the scope can be global, available only to this WorkItem and its descendents, or local to this WorkItem.

 [EventPublication("topic://UpdatesAvailable", PublicationScope.Global)]
public event EventHandler<DataEventArgs<UpdateData>> UpdatesAvailable;
// or
[EventPublication("topic://UpdatesAvailable", PublicationScope.Global)]
public event EventHandler UpdatesAvailable;

Methods can subscribe to events using the EventSubscription attribute on a method declaration, as shown in the following code. More than one method can subscribe to the same event, and you can specify the thread that the event subscription runs on. However, you cannot control which method will execute first because the Publisher-Subscriber pattern decouples publishers from subscribers.

 [EventSubscription("topic://UpdatesAvailable")]
public void SomethingHappened(object sender, DataEventArgs<UpdateData> e)
{ ... }

Services

Services are objects that are used by many components in the application, such as security services, tracing services, and eventing services. The Composite UI Application Block includes interface definitions and implementations of several services used in the application block. For example, it includes the service ModuleLoaderService. The ModuleLoaderService uses the information returned from the service implementation of IModuleEnumerator to determine which modules should be loaded at run time.

Modules

Modules are distinct deployment units of a Composite UI Application Block application. Typically, they include some combination of services, WorkItems, SmartParts, controllers, presenters, and business entities. With modules, you can encapsulate a set of concerns of your application and deploy them to different users or applications.

Examples of modules could be:

  • A module that contains infrastructure services for a specific application type.
  • A module that contains specific application area, such as reports or additional use cases.

The Branch Client reference implementation is composed of multiple modules. The following modules exist as class library projects in the Bank Branch Client solution:

  • Infrastracture.Module
  • BranshSystems.Layout
  • BranchSystems.Module
  • BasicAccounts.Module
  • CreditCardAccounts.Module

Loading Modules

The Composite UI Application Block provides a service to load modules when the application starts. By default, it uses an XML catalog file to determine the modules to load. The default name for this file is ProfileCatalog.xml. The following XML shows the contents of the ProfileCatalog.xml file for the Appraisal Workbench reference implementation.

<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" >
  <Modules>
    <ModuleInfo AssemblyFile="GlobalBank.AppraiserWorkbench.AppraiserWorkbenchModule.dll" />
  </Modules>
</SolutionProfile>
Note You can extend the Composite UI Application Block to retrieve the catalog from other data sources. For example, you could create a component that retrieves the catalog from a centralized location.

Module Initialization

When the Composite UI Application Block loads a module, it uses reflection to determine whether the module includes a class that implements the IModule interface. You implement this interface (typically by deriving from ModuleInit) to initialize and run the module's WorkItems.

Module Dependencies

You can create modules that are independent of one another. You can also create modules that are used by other modules. In the Branch Client reference implementation, multiple modules depend on the BranchSystems.Module module. When one module has a dependency on another module, you express the dependency with the ModuleDependency attribute. For example, the following code expresses a dependency on the BranchSystems.Module.

 [assembly: ModuleDependency("BranchSystems.Module")]

This attribute affects the loading sequence; the Composite UI Application Block will load modules with dependencies after the modules on which they are dependent.

Note The Branch Client reference implementation includes a custom module loader service that allows you to declare module dependencies in the catalog file. This means you do not have to use the ModuleDependency attribute in your source code.

Wiring the Parts Together with the Injection System

A Composite UI Application Block application consists of loosely coupled components (WorkItems, services, SmartParts, controllers, and so on). The components, though independent, collaborate during the execution of a composite smart client solution. To support component independence, a component must be able to use another component without requiring a change to the source code of the component to be used. To support this, the Composite UI Application Block uses dependency injection to create component object instances. When you examine the source code for a Composite UI Application Block application, you will notice that the application does not create instances of another component by directly constructing an object (using new). Instead, the source code for a Composite UI Application Block application contains attributes such as CreateNew and ServiceDependency.

Note A common expression used to explain the attributes is "magic happens." The "magic" is the Composite UI Application Block using ObjectBuilder to provide injection of object instances.

These attributes support the injection of objects at run time. The Composite UI Application Block uses a custom underlying system named ObjectBuilder to create and inject instances of objects of the appropriate type into the application at run time. ObjectBuilder uses the factory pattern to create object instances. It supports a general-purpose attribute-based dependency injection. The attributes determine the type of object that the ObjectBuilder factory creates.

Note ObjectBuilder itself is not a dependency injection system; it is a more general purpose and extensible pipeline that allows you to customize how an object is created. Both Enterprise Library and the Composite UI Application Block use ObjectBuilder to provide for dependency injection.

You can also programmatically (without using attributes) use the ObjectBuilder factory to create instances. Instead of directly constructing an object instance, you use the AddNew method of Composite UI Application Block container classes. For example, when the following code executes, ObjectBuilder creates an instance of the OfficerView class.

WorkItem.SmartParts.AddNew<OfficerView>();

Creating New Objects

Frequently, an object in your application requires an instance of another object. For example, consider the OfficerView SmartPart (view) in the Bank Branch reference implementation. The reference implementation uses the MVP pattern to decouple business logic from the user interface code. This means that the OfficerView SmartPart requires a reference to an instance of a presenter object (in this case, an instance of the OfficerViewPresenter class). Figure 10 illustrates the classes that participate in the MVP pattern.

Aa546409.02-scsf-cabinjection1(en-us,MSDN.10).png

Figure 10. OfficerView MVP pattern

The CustomerWorkItemController class in the Branch Client reference implementation contains the business logic for managing a customer account. Part of its responsibility is to display the OfficerView view. The CustomerWorkItemController class uses the Composite UI Application Block to create an instance of the OfficerView class in its Run method.

private IOfficerView _officerView = null;

public void Run(QueueEntry queueEntry, IWorkspace workspace)
{
   

  _officerView = WorkItem.SmartParts.AddNew<OfficerView>();

   
}

The OfficerView class requires an instance of the OfficerViewPresenter class but does not contain code to instantiate an instance. Instead, the OfficerView class uses the CreateNew attribute.

 [CreateNew]
public OfficerViewPresenter Presenter
{
  set
  {
    _presenter = value;
    _presenter.View = this;
  }
}

The CreateNew attribute instructs ObjectBuilder to instantiate and initialize an instance of an OfficerViewPresenter when the OfficerView is created. When the property is set, the View property of the presenter is used to connect this implementation of the IOfficerView interface to the presenter (the View property is defined in the Presenter base class).

Registering a Constructor

A class can contain more than one constructor. ObjectBuilder first looks for any constructor decorated with the [InjectionConstructor] attribute (there can be only one of these) and uses this constructor if found. If there is no decorated constructor, yet there is only one constructor, it will use that constructor.

 [InjectionConstructor]
public OfficerPanelViewPresenter(...)
{
   
}

Locating a Service

You can add the ServiceDependency attribute to a property in your class to obtain a reference to a service declaratively. The property specifies the type of service or interface you require, as shown in the following code. When this attribute is present, ObjectBuilder locates an instance of the service and passes back a reference to it. To locate the service, ObjectBuilder first looks in the current WorkItem. If the service is not found, ObjectBuilder then looks at the services in the parent WorkItem. This process continues until the service is located or ObjectBuilder reaches the root WorkItem. If the service is not found, ObjectBuilder throws an exception.

private IMyService service;

[ServiceDependency]
public IMyService MyService
{
  set { service = value; }
}

Frequently, the ServiceDependency attribute is used for the arguments in a constructor. This means that ObjectBuilder will instantiate the required services when it creates the dependent object.

private ICustomerQueueService _queueService = null;

[InjectionConstructor]
public OfficerPanelViewPresenter
  (
    [ServiceDependency] ICustomerQueueService queueService
  )
{
  _queueService = queueService;
}

Registering a Service

You can use the Service attribute on a public class to declare a class to be registered as a service in the root WorkItem. The Composite UI Application Block infrastructure creates an instance of this class and registers it as a service during application startup. The constructor parameter tells the Composite UI Application Block that, for location purposes, the interface key to use for the registration of the service. For example, the following code registers the MyService class with the IMyService key. This means that this service can be located with a ServiceDependency attribute value of IMyService.

 [Service(typeof(IMyService))]
public class MyService : IMyService
{

}

You can also programmatically register a service. To do this, call the Add or AddNew method of the Services collection of the WorkItem within which you want to use the service. This can be the root WorkItem or another WorkItem that you create. To use an existing service instance you have already created, use the Add method. You could use the following code in an override of the Start method in your custom application class.

RootWorkItem.Services.Add<CustomerService>(myServiceInstance);

Patterns and Practices home

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker