Shell and View
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 specify the views that will appear. It may also define certain top-level UI elements, such as the main menu and toolbar. The shell defines the overall appearance 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 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 or controls 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 appears 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.
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 user interface elements that are part of the shell. This includes defining several regions to which modules add their views. The area where the buy and sell transactions show up in the Stock Trader RI is a region known as the action region, defined as follows.
<ContentControl Regions:RegionManager.RegionName="ActionRegion" … >
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 and Silverlight, 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 and Silverlight provide mechanisms to do this. 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 WPF 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 WPF 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. For more information about how to add views to regions, see "Displaying Views" in UI Composition technical concept.
Views in the Stock Trader RI
Figure 2 earlier in this topic highlights seven different views. In what the user sees as a research bar on the right side of the screen, there are really three views plugged in by modules offering charting and other controls. The main content area of the Stock Trader RI is a tab control with a single view on the currently selected tab. The buy and sell views appear in a lower region and each buy or sell transaction consist of an individual view. For more informaton about the organization of the Stock Trader RI, see the Stock Trader Reference Implementation.
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 Presenter 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. This is a problem particularly when unit testing your view if it derives from, or depends on, running WPF or Silverlight components as part of its execution context. To make sure you can test the view logic without these dependencies, you need to be able to mock the view to remove the dependencies on the execution context, which requires separate classes 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 that is required for testability also helps make the view easier to maintain.
More Information
For more information about other Composite Application Guidance technical concepts, see the following topics: