Chia sẻ qua


UI Composition QuickStart

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The UI Composition QuickStart demonstrates how to build a Windows Presentation Foundation (WPF) user interface composed of different views that are dynamically loaded into regions and that interact with each other in a decoupled way.

Business Scenario

The UI Composition QuickStart is based on a fictitious resource management system. The main window represents a subset of a larger system. In this window, the user can review detailed information about employees of a company. Figure 1 illustrates the QuickStart's main window.

Ff649188.f54ef5da-c44d-4060-819c-f458cdb1da6a(en-us,PandP.10).png

Figure 1
UI Composition QuickStart

Building and Running the QuickStart

The QuickStart ships as source code, which means you must compile it before running it. This QuickStart does not have any prerequisites.

To build and run the QuickStart

  1. Run the file Open QS-UI Composition Quickstart Solution.bat to open the solution in Visual Studio.
  2. On the Build menu, click Rebuild Solution.
  3. Press F5 to run the QuickStart.

Walkthrough

Perform the following steps in the UI Composition QuickStart to explore the business scenario.

To explore the business scenario

  1. Run the file Open QS-UI Composition Quickstart Solution.bat to open the solution in Visual Studio.

  2. On the Build menu, click Rebuild Solution.

  3. Press F5 to run the QuickStart. The main window shows a list of employees, as illustrated in Figure 2.

    Ff649188.9d2d90cf-ef24-4ab6-8e81-fe1b22605785(en-us,PandP.10).png

    Figure 2
    QuickStart main window

  4. Select an employee. This dynamically loads a view that shows the employee details, as shown in Figure 3.

    Ff649188.7c40d0ab-010e-4505-a169-3ecc7ea70989(en-us,PandP.10).png

    Figure 3
    The General tab for a selected employee

  5. Explore the different tabs. Each tab provides additional information about the employee. Figure 4 shows the Current Projects tab.

    Ff649188.9fed986b-ed3a-4a85-bc8f-0867f19cf7e9(en-us,PandP.10).png

    Figure 4
    The Current Projects tab for a selected employee

Implementation Notes

The QuickStart highlights the key implementation details of an application that leverages the usage of regions. The key artifacts in the application are illustrated in Figure 5.

Ff649188.4876ecec-7949-4b3d-b9f6-2e3ec8481582(en-us,PandP.10).png

Figure 5
UI Composition QuickStart conceptual view

The artifacts illustrated in Figure 6 are the following:

  • Shell window. This is the application's main window. This window contains the main region.
  • Employees view. This view is the main view of the Employees module. It hosts the Employees List view and contains the details region, where instances of the Employees Details view are loaded.
  • Employees List view. This view displays a list of employees.
  • Employees Details view. This view displays detailed information for an employee and contains a Tab Region.
  • Projects List view. This view displays the list of projects an employee is working on.
  • Employees Controller. This controller coordinates the interaction of the Employees module's views.

The next sections describe each artifact in greater detail.

Shell Window

The Shell window defines a single region that is the main region of the application. The region is defined in the Shell window's XAML markup file (this file is located at UIComposition\Shell.xaml), as shown in the following code.

<ItemsControl cal:RegionManager.RegionName="{x:Static infrastructure:RegionNames.MainRegion}" />

Note that a constant is used for the region's name. This constant is defined in the RegionNames class of the UIComposition.Infrastructure project (the class file is located at UIComposition.Infrastructure\RegionNames.cs).

Employees View

The Employees view is a view that contains ContentControl controls where children views can be placed. The view implementation is split in multiple files inside the folder UIComposition.Modules.Employee\Views\EmployeesView.

The following code shows the markup of the view where two ContentControls controls are defined.

<StackPanel x:Name="EmployeesPanel">
    <ContentControl x:Name="HeaderPanel"/> 
    <ContentControl x:Name="DetailsPanel" cal:RegionManager.RegionName="{x:Static local:RegionNames.DetailsRegion}"/>
</StackPanel>

In the preceding code, the following ContentControl controls are defined:

  • HeaderPanel. This control will hold the Employees List view.
  • DetailsPanel. This control defines a region named DetailsRegion. In this region, instances of the Employees Details view will be loaded when an employee is selected in the Employees List view. In this region, only one view at a time will be displayed.

The Employees view is added to the main region by the Employees module initializer class (located at UIComposition.Modules.Employee\EmployeeModule.cs) when the application starts. The following code shows the Initialize method of this class, where the view is added to the main region.

public void Initialize()
{
    this.RegisterViewsAndServices();

    EmployeesPresenter presenter = this.container.Resolve<EmployeesPresenter>();

    IRegion mainRegion = this.regionManager.Regions[RegionNames.MainRegion];
    mainRegion.Add((UIElement)presenter.View);
}

Employees List View

The Employees List view displays a list of employees from which the user can select. The view implementation is in the folder UIComposition.Modules.Employee\Views\EmployeesListView. Figure 6 shows the Employees List view.

Ff649188.73eb6816-7b01-45d7-bd69-29f83e658f91(en-us,PandP.10).png

Figure 6
Employees List view

When an employee is selected, the view raises an event named EmployeeSelected. This event is handled by the Employees Controller, which, in turn, loads the Employees Details view corresponding to the selected employee into the DetailsRegion region. For more details about the Employees Controller, see the section "Employees Controller" later in this topic.

Note

The Employees List view is not loaded into a region; instead, it is added to the HeaderPanelContentControl control directly by the Employees view's presenter (located at UIComposition.Modules.Employee\Views\EmployeesView\EmployeesPresenter.cs). In this case, a region is not a requirement because there is a single instance of this view during the application lifetime, and no views are added or removed to the HeaderPanel control other than the Employees List view.

Employees Details View

The Employees Details view displays detailed information for a single employee, as illustrated in Figure 7.

Ff649188.37f6342c-999b-4ee2-a041-a8731559c3f2(en-us,PandP.10).png

Figure 7
Employees Details View

This view contains a TabControl control, which is used as a region. The TabControl contains two tabs by default (defined in the view's XAML markup code): one that displays the employee's general information and one that shows the employee's location in Live Search maps. Because the TabControl is a region, it acts as an extension point for the view because child views can be dynamically added in a decoupled way. To demonstrate this, in this region, an instance of the Project List view is dynamically added when the user selects an employee in the Employees List view.

The following code shows the XAML code of the view where the TabControl is defined.

<StackPanel>
    <TabControl x:Name="DetailsTabControl"cal:RegionManager.RegionName="{x:Static local:RegionNames.TabRegion}">
        <TabControl.ItemContainerStyle>
             ...
        </TabControl.ItemContainerStyle>
        <TabItem x:Name="GeneralTabItem" Header="General">
   ...
        </TabItem>
        <TabItem Header="Location">
             ...
        </TabItem>
    </TabControl>
</StackPanel>

The view's implementation is located in the folder UIComposition.Modules.Employee\Views\EmployeesDetailsView.

Projects List View

The Projects List view shows the projects on which an employee is currently working. This view is dynamically loaded inside the TabRegion region of the Employee Details view when an employee is selected in the Employees List view. Figure 8 illustrates the Projects List view.

Ff649188.ba129f0b-d0ea-471d-a2cd-79e766021004(en-us,PandP.10).png

Figure 8
Projects List view

Employees Controller

This class, implemented in the file UIComposition.Modules.Employee\Controllers\EmployeesController.cs, manages the interaction of the Employees module's views. The class's main logic resides in the OnEmployeeSelected method, as shown in the following code. This method is the event handler for the EmployeeSelected event raised by the Employees List view when the user selects an employee.

public virtual void OnEmployeeSelected(BusinessEntities.Employee employee)
{
    IRegion detailsRegion = regionManager.Regions[RegionNames.DetailsRegion];
    object existingView = detailsRegion.GetView(employee.EmployeeId.ToString());

    if (existingView == null)
    {
        IProjectsListPresenter projectsListPresenter = this.container.Resolve<IProjectsListPresenter>();
        projectsListPresenter.SetProjects(employee.EmployeeId);

        IEmployeesDetailsPresenter detailsPresenter = this.container.Resolve<IEmployeesDetailsPresenter>();
        detailsPresenter.SetSelectedEmployee(employee);

        IRegionManager detailsRegionManager = detailsRegion.Add(detailsPresenter.View, employee.EmployeeId.ToString(), true);
        IRegion region = detailsRegionManager.Regions[RegionNames.TabRegion];
        region.Add(projectsListPresenter.View, "CurrentProjectsView");
        detailsRegion.Activate(detailsPresenter.View);
    }
    else
    {
        detailsRegion.Activate(existingView);
    }
}

In the preceding code, the DetailsRegion region is obtained, and then an Employees Details view corresponding to the selected employee is retrieved from the region. If the view exists, it means that the employee has been previously selected; therefore, that view is activated (see the else statement). If the view does not exist, it needs to be created and shown in the user interface. The following lines (extracted from the if statement of the preceding code) contain the logic required to create and show the Employees Details view for the selected employee.

IProjectsListPresenter projectsListPresenter = this.container.Resolve<IProjectsListPresenter>();
projectsListPresenter.SetProjects(employee.EmployeeId);

IEmployeesDetailsPresenter detailsPresenter = this.container.Resolve<IEmployeesDetailsPresenter>();
detailsPresenter.SetSelectedEmployee(employee);

IRegionManager detailsRegionManager = detailsRegion.Add(detailsPresenter.View, employee.EmployeeId.ToString(), true);
IRegion region = detailsRegionManager.Regions[RegionNames.TabRegion];
region.Add(projectsListPresenter.View, "CurrentProjectsView");
detailsRegion.Activate(detailsPresenter.View);

In the preceding code, first, a presenter of the Project List view is resolved and the projects list is initialized for the selected employee. This view will be added later to the TabRegion region of the Employees Details view. Second, a presenter for the Employee Details view is resolved and the selected employee is passed to it. After that, the Employee Details view is added to the DetailsRegion region, with the employee's identifier as the view's name. By associating the employee's identifier with the view, the view can be later looked up in the region to display it if the employee is selected again.

The following code shows the line where the Employee Details view is added to the DetailsRegion region.

IRegionManager detailsRegionManager = detailsRegion.Add(detailsPresenter.View, employee.EmployeeId.ToString(), true);

Note that in the preceding code, the flag createRegionManagerScope is set to true. This means that the added view will define a new region scope, and therefore, all the regions registered by the view and child views will not be registered in the Shell's region manager; instead, regions will be registered in a new region manager associated to the view. In the preceding code, a reference to this new region manager is stored in the detailsRegionManager variable.

Finally, the TabRegion region of the recently created Employees Details view is obtained through the detailsRegionManager, the Projects List view is added to it, and the Employee Details view is activated. The following code shows how this logic is implemented:

IRegion region = detailsRegionManager.Regions[RegionNames.TabRegion];
region.Add(projectsListPresenter.View, "CurrentProjectsView");
detailsRegion.Activate(detailsPresenter.View);

Acceptance Tests

The UI Composition QuickStart includes a separate solution that includes acceptance tests. The acceptance tests describe how the application should perform when you follow a series of steps; you can use the acceptance tests to explore the functional behavior of the application in a variety of scenarios.

Some acceptance tests were developed using the testing framework White. To run these tests, you need to have White installed. For more information about White, including download information, see White on CodePlex.

Note

The acceptance tests have been developed and verified with the White 0.1.5.0 release. Although other releases of White might work too, it is recommended to use the aforementioned release to avoid any issues when running the tests.

To run the UI Composition QuickStart acceptance tests

  1. Place the assemblies required by White in the folder Source\Lib\White. The files are the following:
    • Bricks.dll
    • Bricks.RuntimeFramework.dll
    • Castle.Core.dll
    • Castle.DynamicProxy2.dll
    • Core.dll
    • log4net.config
    • log4net.dll
    • nunit.framework.dll
    • White.NUnit.dll
    • Xstream.Core.dll
  2. In Visual Studio, open the solution file QuickStarts\UIComposition\UIComposition_AcceptanceTests.sln.
  3. Right-click UICompostion.Tests.AcceptanceTests, and then click Set as StartUp Project.
  4. Press F5.

Outcome

You should see the QuickStart window and the tests automatically interact with the application. At the end of the test pass, you should see that all tests have passed.

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.