Partager via


Shell and View

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 shell is the main window of the application where the primary user interface (UI) content is contained. The shell may be composed of multiple windows if desired, but most commonly it is just a single main window that contains multiple views. The shell may contain named regions where modules can add views. It may also define certain top-level UI elements, such as the main menu and toolbar. The shell also defines the overall appearance and behavior (look and feel) for the application. It may define styles and borders that are present and visible in the shell layout itself, and it may also define styles, templates, and themes that get applied to the views that are plugged into the shell.

Views are the composite portions of the user interface that are contained in the shell's window(s). It is easiest to think about a view as a user control that defines a rectangular portion of the client area in the main window. However, views in the Composite Application Library do not have to be defined with a user control. You can use a Windows Presentation Foundation (WPF) data template to define a view that will be rendered based on the data in your model. A view could also share screen real estate with other views due to the rendering and compositing capabilities of WPF. In simple terms, a view is just a collection of user interface elements that define part of the rendering of the user interface. It is a unit of encapsulation for defining the separable portions of your UI.

Implementing a Shell

You do not have to have a distinct shell as part of your application architecture to use the Composite Application Library. If you are starting a new composite WPF application from the very beginning, implementing a shell provides a well-defined root and initialization pattern for setting up the main user interface of your application. However, if you are adding Composite Application Library features to an existing application, you do not have to change the basic architecture of your application to add a shell. Instead, you can alter your existing window definitions to add regions or pull in views as needed.

You can also have more than one shell in your application. If your application is designed to open more than one top level window for the user, each top level window act as shell for the content it contains.

Stock Trader RI Shell

The Stock Trader Reference Implementation (Stock Trader RI) has a shell as its main window. In Figure 1, the shell and views are highlighted. The shell is the main window that gets shown when the Stock Trader RI starts, and which contains all the views. It defines the regions into which modules add their views and a couple of top-level UI items, including the CFI Stock Trader title and the Watch List tear-off banner.

Ff649356.13a42341-1572-44a0-b52e-3d46ab91a6a9(en-us,PandP.10).png

Figure 1
Stock Trader RI shell window and highlighted views

The shell implementation in the Stock Trader RI is provided by Shell.xaml and its code-behind file Shell.xaml.cs. Shell.xaml includes the layout and UI elements that are part of the shell. This includes defining several ItemsControls that are identified as regions for modules to add their views to, as shown here.

<ItemsControl Margin="0,20,0,0" cal:RegionManager.RegionName="NewsRegion" />

The only thing included in the code-behind file is the implementation of the IShellView interface defined in the Shell project, as shown here.

public interface IShellView
{
   void ShowView();
}

The implementation of ShowView simply calls Show on the shell class itself, which displays the main window. ShowView is called by the bootstrapper in the initialization of the application, as shown in the following code. For more information, see "Creating the Shell" in the Bootstrapper technical concept.

public partial class Shell : Window, IShellView
{

    public Shell()
    {
        InitializeComponent();
    }

    public void ShowView()
    {
        this.Show();
    }
}

Implementing a View

Views are the main unit of UI construction within a composite UI application. You can define a view as a user control, data template, or even a custom control. A view encapsulates a portion of your user interface that you would like to keep as decoupled as possible from other parts of the application. You may choose what goes in a view based on only encapsulation or a piece of functionality, or you may choose to define something as a view because you will have multiple instances of that view in your application.

Because of the content model of WPF, there is nothing specific to the Composite Application Library required to define a view. The easiest and most common way to define a view is to define a user control. To add a view to the UI, you simply need a way to construct it and add it to a container. WPF provides mechanisms to do that out of the box. The only thing the Composite Application Library adds is the ability to define a region into which a view can be dynamically added at run time.

The following markup shows an example user control.

<UserControl x:Class="WpfApplication1.ExcessivelySimpleView"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Height="25" Width="100">
    <Label>A VERY simple view</Label>
</UserControl>

The following markup shows an example data template.

<Window x:Class="WpfApplication1.Window1" .../>
    <Window.Resources>
        <DataTemplate x:Key="ADataTemplateView">
            <Label>A really simple data template view</Label>
        </DataTemplate>
    </Window.Resources>
    <Grid .../>
</Window>

Composite Views

Frequently, a view that is supporting a specific set of functionality can get complicated. In that case, it may make sense to break up the view into several child views and have the parent view handle constructing itself using the child views as parts. It may do this statically at design time, or it may support having modules add child views through a contained region at run time. When you have a view that is not fully defined in a single view class, you can refer to that as a composite view. Frequently, a composite view is responsible for constructing the child views and for coordinating the interactions between them. Child views can also be designed to be more loosely coupled from their sibling views and their parent composite view by using the Composite Application Library commands and the event aggregator.

Views in the Stock Trader RI

Figure 1 earlier in this topic highlights five different views. In what the user sees as a main toolbar, there are really two views plugged in by modules that are composed of buttons and other toolbar controls. The main content area of the Stock Trader RI is a composite view with three child views, the position grid, and two chart control instances. The watch list and news articles are also individual views. The view illustrated in Figure 1 does not display buy/sell orders, which are defined as composite views themselves, and they are hosted in an ItemsControl-based region on another tab in the main content area.

Views and Design Patterns

You should consider using one of several user interface design patterns when implementing a view even though it is not required by the Composite Application Library. The Stock Trader RI and QuickStarts demonstrate both the Supervising Controller and Presentation Model patterns as a way to implement a clean separation between the view layout and the view logic.

Separating the logic from the view is important for both testability and maintainability. If you create a view with a user control or custom control and put all the logic in the code behind, it can be difficult to test because you have to create an instance of the view to unit test the logic. However, sometimes the base class of the view can interfere with testing because it expects only the class to be created as part of a user interface in a normal WPF execution context. To make sure the right things happen in the view as part of your unit tests, you will also need a way to mock out the views, which really requires a separate class for the view and the logic. If you define a view as a data template, there is no code associated with the view itself, so you have to put the associated logic somewhere else. The same clean separation of logic from layout required for testability also helps make the view easier to maintain.

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.