Intersoft ClientUI Documentation
Region Manager Overview

This topic discusses the concepts and design patterns that can be applied to achieve view extensibility in Silverlight and WPF applications. This topic also explains the view extensibility library available in ClientUI Framework, and overviews the best practices and guidelines to implement the view extensibility based on various scenarios.

This topic contains the following sections:

Understanding View Extensibility

In software development, extensibility is an important aspect that needs thoughtful consideration in order to build quality applications that are easy to maintain and extend in the future. Furthermore, extensible applications allow developers to rapidly adapt to the dynamic changes usually required in business specifications.

One of the important extensibility aspects to consider in the early development phase is regarding view extensibility. For basic understanding, let's presume you have an application that shows a list of quick tasks such as illustrated below.

Initially, your application might contain only a few modules such as Customers, Products, and Reports. Next, you define them in the navigation list such as shown in the illustration above. As you added more modules, you have to revisit and modify the navigation list, add the new links and so forth. The way the view is implemented in this example indicates the lacking of extensibility design pattern.

The ability to add the navigation links when new modules become available without modifying the original co debase is the essence of view extensibility. View extensibility introduces a number of benefits that allow you to accelerate the development time and minimizes code changes.

Exploring View Extensibility Patterns: View Injection and View Discovery

There are two well-known patterns to achieve view extensibility called View Injection and View Discovery.

View injection is a pattern that dynamically inject an element to the target at runtime. The view injection is usually done manually by the controller at a certain event, such as page load. In contrast to view injection, the view discovery pattern performs the injection automatically when the element becomes available in the application life cycle. View discovery is usually implemented with metadata (also known as attribute in .NET) to allow the view to be discovered at runtime. More details on the patterns implementation are discussed in the section below.

Both patterns are commonly implemented along with so called Region Manager, which acts as the controller that reside in the application’s shell. A region manager can consist of multiple regions which represent the target placeholder for injection.

At a glance, the following illustration shows how the view injection/discovery works together with region manager.

 

Introducing ClientUI Region Manager

Built from the ground up, ClientUI Region Manager is specifically designed for use in multi-page applications. It supports view extensibility through both view injection and view discovery methods.

With page-aware region manager concept, you can simply define the region manager and the associated regions in the pages without needing to know when the regions need to be instantiated or activated. When the page is activated (either through browser journal navigation or navigation link), the defined regions in the page will be automatically filled with the injected view content. This allows view extensibility to be achieved with loose coupling approach.

The following illustration shows the region manager concept implemented in ClientUI.

As seen in the above illustration, the main goal of the page-aware region manager is to streamline modular application development in which the application may contains multiple pages or even content that is loaded on demand. It allows you to define the region scopes and the regions in each page without concerning when to instantiate or disposing the regions – the framework does it all behind the scene.

Implementing View Injection

The first step to implement view injection is defining the region manager and regions of the containers that will participate in the view extensibility. The containers can be a simple content control, items control, tab controls, window controls – or any control types that serve as containers.

The ClientUI Region Manager provides a set of attached properties that allow you to define the regions declaratively in XAML. For the page container to participate as extensibility host, you need to specify at least two of the provided attached properties which are RegionManager.IsRegionScope and RegionManager.ScopeName property. Once the region manager is set, you can define the controls to be extended through the Region.RegionName attached property.

The following example shows the region manager and scope definition in the UXPage, followed with the region definition for the target container.

C#
Copy Code
<Intersoft:UXPage 
        Intersoft:RegionManager.IsRegionScope="True" 
        Intersoft:RegionManager.ScopeName="Home">

    ...

    <Intersoft:GroupBox Header="Quick Tasks">
        <Intersoft:UXItemsControl Intersoft:Region.RegionName="QuickTasks">
            <Intersoft:UXHyperlinkButton Content="View Top Customers"/>
            <Intersoft:UXHyperlinkButton Content="Manage Products"/>
            ...
        </Intersoft:UXItemsControl>
    </Intersoft:GroupBox>

</Intersoft:UXPage>

Once the regions are defined, you can now access to these regions using the region manager API. This allows you to instantiate the view element and inject it to the target region from either code behind or ViewModel. Often times, you might want to do the injection in the bootstrapper where the application module is first loaded.

The following example shows how to add a view element to a specific region when the particular module is loaded.

C#
Copy Code
public class AppInitializer : IApplicationInitializer
{

    #region IApplicationInitializer Members

    public void Initialize(ApplicationPackage package)
    {
        // add new links to the Quick Tasks region on-demand ("view injection") when this XAP is loaded
        RegionManager manager = RegionManagerService.FindRegionManager("Home") as RegionManager;

        manager.AddViewToRegion("QuickTasks",
            new UXHyperlinkButton()
            {
                Content = "New Link 1",
                Foreground = new SolidColorBrush(Colors.Red)
            });

        manager.AddViewToRegion("QuickTasks",
            new UXHyperlinkButton()
            {
                Content = "New Link 2",
                Foreground = new SolidColorBrush(Colors.Red)
            });
    }

    #endregion
}

Implementing View Discovery

Similar to the view injection, you always need to define the region manager and regions in the views that will be extended.

The difference with the view injection is that you don’t write code to inject the element to the target region. Instead, you simply add decorator attributes to the class that will be injected to the target region. When the target region is loaded, it will discover all views that should be injected based on the metadata, hence the injection is processed seamlessly and automatically.

The following code shows an example of view discovery implementation.

C#
Copy Code
[ViewPart("Home", "Overview")]
public partial class Overview : UserControl
{
    public Overview()
    {
        InitializeComponent();
    }
}

The ViewPart attribute above basically states that the Overview class should participate in the view discovery process which target the Home region scope and Overview region.

The following illustration shows the application before and after the view is discovered.

Comparing both view extensibility approaches, the view discovery is arguably the easiest and most efficient way to achieve the view extensibility goals. It's highly recommended to use view discovery pattern whenever possible, unless you need to inject the view based on certain conditions or complex business logics.

Built-in Region Adapters

As discussed in previous sections, ClientUI Region Manager is the core service that handles the injection between the actual view elements and the regions. In fact, Region Manager serves as the abstraction of views (user interface) that allows the models

In order for the Region Manager to work, it needs to understand how the region manager interacts with its children in the container. The facade that provides knowledge about how the region manager should work is called region adapter. In fact, each container type supported in the Region Manager has their own region adapter implementation.

The following illustration shows the region adapter role in the Region Manager extensibility concept.

 

ClientUI ships with four built-in region adapters as follows:

Similar to the SelectionControlRegionAdapter, the TabControlRegionAdapter also supports view activation and deactivation. When activated, the specified tab item will be set as active.

ClientUI Framework Integration

Integration with Application Framework

ClientUI Region Manager supports view injection through view discovery where a particular view type will be automatically injected to the specified region. In most cases, the view discovery happened when the view type becomes available (or technically, loaded into the application domain). When used together with ClientUI Application Framework that provides dynamic application package (XAP) loading, it makes perfect sense to discover the view types that participate with the view extensibility when the application package is downloaded and loaded to the application framework.

For more information about ClientUI Application Framework, see Application Framework Overview.

By default, the Application Framework will not automatically discover the types in the downloaded modules. To enable the view discovery, set the EnableViewDiscovery property of the ApplicationPackage to true. See the following example for more details.

C#
Copy Code
ApplicationPackage package = new ApplicationPackage()
{
    Name = "ClientUI_Module_Home",
    Source = new Uri("ClientUI_Module_Home.xap", UriKind.RelativeOrAbsolute),
    Size = -1,
    EnableMetadataDiscovery = true,
    EnableViewPartDiscovery = true
};

UXShell.Current.Applications.Add(package);

// download and load both packages
package.Download(true);

However, if your modules are downloaded automatically - such as during navigation or window launch command - instead of programmatically, you can define the attribute in the metadata file of the application package. The ClientUI application metadata file usually resides in the root project of the application and named SAFMetadata.xml.

The following shows the example of ClientUI application metadata with automatic view discovery definition.

XML
Copy Code
<ApplicationPackage xmlns="http://intersoft.clientui.com/schemas"
    ID="ClientUI_Module_Home"
    Name="ClientUI_Module_Home"
    MainType="ClientUI_Module_Home.MainPage"
    EnableViewPartDiscovery="true">
    
</ApplicationPackage>
It is highly recommended to add the definitions in the metadata file of each application package which allows maximum loose coupling in modular application development. Resort to the programmatic approach only when you don't have access to the project source.

Integration with Navigation Framework

In addition to the view injection, another common extensibility scenario in Silverlight and WPF applications is navigation injection which is important to allow dynamic navigation pages to be discovered when the module is loaded on demand. This is particularly useful in modular navigation applications where the shell does not have any knowledge of the modules that will be loaded. Naturally, the shell does not have any knowledge of the navigation URIs contained in the modules and may not be able to perform navigation properly.

With the introduction of view extensibility in this release, the ClientUI Navigation Framework has been enhanced to support the navigation extensibility. This allows the shell to aware of the navigation URIs of the loaded modules which are required to perform the navigation properly, i.e., supporting navigating from browser address bar, or navigating from a hyperlink button.

The following code shows how to mark a view type to participate in the navigation extensibility.

C#
Copy Code
[NavigableViewPart(NavigableRegions.Module1)]
public partial class UXPage1 : UXPage
{
    public UXPage1()
    {
        InitializeComponent();
    }

    // Executes when the user navigates to this page.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }
}

The final step is adding the KnownUri attribute to the metadata file of the application package. The KnownUri should be identical to the URI registered in the NavigableViewPart attribute. See the following example of the SAFMetadata.xml definition.

XML
Copy Code
<ApplicationPackage xmlns="http://intersoft.clientui.com/schemas"
    ID="ClientUI_Module_Home"
    Name="ClientUI_Module_Home"
    MainType="ClientUI_Module_Home.MainPage"
    EnableViewPartDiscovery="true"
    KnownUri="/Module1"
>
    
</ApplicationPackage>

If you have multiple URI to register, please specify the URIs followed by a comma as the separator.

See Also