UI Composition
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. |
Composite applications typically compose their user interfaces (UIs) from various loosely coupled visual components, otherwise known as views, to deliver an integrated application experience. To the user, the application appears as a seamless program that offers many capabilities. For example, the Stock Trader Reference Implementation (Stock Trader RI) has the views illustrated in Figure 1.
Figure 1
Stock Trader RI views
There are many different challenges for composing the UI. The following are common challenges that are illustrated in the Stock Trader RI and enabled through the Composite Application Library.
- Layout
- Commanding
- Eventing
The next sections describe each of these in greater detail.
Dynamic Layout
In a composite application, views from multiple modules are displayed at run time. Because of this, the application needs a mechanism for specifying how they are laid out. There are several approaches to do this.
View Injection
In this approach, the application contains a registry of reserved locations in the UI. A module can access one of the locations in the registry and use it to inject views. The view being injected does not have any specific knowledge of how it will be displayed in that location. The place it is being injected is referred to by a moniker, such as the name. Each of the objects in the registry implements a specific interface that is used to inject the view. Figure 2 illustrates the View Injection approach to dynamic layout.
Figure 2
View injection
The Composite Application Library introduces the concept of a region. Regions are defined through attached properties in XAML. Regions and the Region Manager together implement view injection. The Stock Trader RI uses regions for composing its UI. For more information about regions, see the Region technical concept or UI Composition QuickStart.
View Discovery
With View Discovery, the modules register their views (or presenters) in a central location, such as in the container, using a well-known interface. A shell service or a composite view then queries the container to discover the views that were registered. After they are discovered, the service lays out those views on the screen as appropriate, such as adding them to a panel or an items control. If after the application is loaded, additional views need to be displayed, such as a new order screen, the shell service or composite view should be notified to handle the display. Figure 3 illustrates the View Discovery approach to dynamic layout.
Figure 3
View discovery
In the Stock Trader RI, the TrendLinePresenter is registered in the container by the market module and retrieved from the container by the PositionSummaryPresentationModel. The PositionSummaryPresentationModel then calls a method on its view (which is a composite view) to handle the display of the trend line.
Commanding
In a composite WPF application, separated presentation patterns, such as Model-View-Presenter, PresentationModel, and Model-View-ViewModel, are used for decoupling the view from the business logic. How then, are actions within the view routed to the appropriate handlers outside of the view? How are the UI elements associated with those actions enabled or disabled based on state changes within the application?
WPF introduces the concept of commands to allow this to occur. UI elements can be bound to a command, which handles the execution logic. After it is bound, it can execute the command, and the element will be automatically enabled or disabled along with the command. The default RoutedUICommand mechanism requires event handlers to be defined in the receiving view. RoutedUICommands can also only be received by UI elements in the visual tree, which is often not the case in a composite application. Additionally, there are complex scenarios in composites where the handling of the command is delegated to child commands.
To overcome this constraint, you can use WPF to create custom ICommands so that you can directly route the handling logic. Two common approaches are delegation and composition.
Delegation
In this method, a command is used that delegates off its handling logic, either through events or delegates where it can be handled externally by a class such as a presenter, service, controller, and so on. This provides the benefit of not having to put any code in the code behind. The command requires two handlers: one for the Execute method and one for the CanExecute method. Whenever the Execute or CanExecute methods are called on the command, the handlers are called either through the event being raised or the delegate being invoked. Figure 4 illustrates the Delegation approach to commanding.
Figure 4
Delegation
Composition
Composition is a variation of delegation. In this approach, a composite command delegates off its handling logic to a set of child commands, such as in a Save All scenario described earlier. The composite command needs to provide a way for the child commands to be registered. Executing the composite command executes the children. The composite commands CanExecute returns false, unless all the children return true.
The Composite Application Library introduces the DelegateCommand<T> and CompositeCommand classes as implementations of these approaches. For more information about commands, see the Commands technical concept or Commanding QuickStart. Figure 5 illustrates the Composition approach to commanding.
Figure 5
Composition
Eventing
In a composite application, components, such as presenters, services, and controllers, residing in different modules often need to communicate with one another based on state changes. This is a challenge due to the highly decoupled nature of a composite application because the publisher has no connection to the subscriber. Additionally, there may be threading issues because the publisher is on a different thread than the subscriber.
The Pub/Sub pattern addresses these challenges. There are several ways to implement the pattern. Two approaches used in the Composite Application Guidance are Event Services and Event Aggregation.
Event Services
In this method, an application-specific service raises standard .NET Framework events. To add new events, the service and service interface need to be modified. This service is registered in the container where it can be accessed by the different modules in the system. The publisher and the subscriber reference the service interface and do not depend on one another. Using this approach, the subscriber needs to manually handle any thread marshaling concerns and handle unregistering itself from the event so that it can be garbage collected. Figure 6 illustrates the Event Services approach.
Figure 6
Event Services
Event Aggregation
This approach uses a generic event aggregator service registered in the container that holds a repository of event objects. The event object itself uses delegates instead of events. The advantage of this is that these delegates can be created at the time of publishing and immediately released, which does not prevent the subscribers from being garbage collected. Each event object contains a collection of subscribers it will publish to. New events can be added to the system without modifying the service. The event object can also automatically handle marshaling to the correct thread.
The EventAggregator service and CompositeWpfEvent class are implementations that exist in the Composite Application Library. For more information, see the Event Aggregator technical concept and Event Aggregator QuickStarts. Figure 7 illustrates the Event Aggregation approach.
Figure 7
Event Aggregation
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. |