Contents

Overview

WPF/CAB Shell is a sample that is intended to serve as a starting point for many WPF/CAB applications. It is not meant to be a 100% fit for all applications. You may need to supplement it or tailor it to your particular needs. However, it will almost certainly have something of value to you if you're writing a WPF application that leverages CAB.

Primarily, it provides a plugin system and a number of services that are typical for most LOB applications. The key goal of the WPF/CAB Shell is to reduce the amount of work necessary for module developers to integrate successfully with the shell.

The WPF/CAB Shell sample can be found under the Samples folder in the SCSFContrib source download.

Plugin Design

The backbone of the WPF/CAB Shell is its plugin design. If you're familiar with CAB, you're probably aware of its ability to dynamically enumerate and load modules. The plugin system provided with the WPF/CAB Shell extends this notion and provides additional functionality on top.

All DLLs under the Plugins directory in the application deployment directory will be treated as plugins. Directories are searched recursively, so you can use any naming scheme you like for directories under the Plugins directory. It also means that you can deploy multiple versions of the same plugin.

Plugins in the WPF/CAB Shell come in two basic varieties:
  • Implicitly trusted
  • Untrusted

Implicitly trusted plugins are those that have been signed with a special key. These plugins will be automatically loaded by the shell if they are found. Untrusted plugins are those that are not signed with the special key. These plugins are not loaded by default, and will only be loaded if the user explicitly indicates that they would like to do so.

The key used to sign trusted plugins is included in the download and is called TrustedModule.snk, but you should generate your own. Otherwise, anyone will have the ability to create implicitly trusted plugins for your application. To change it, simply use the sn.exe SDK tool and replace the TrustedModule.snk file, and then update the WhitelistModuleEnumerator._trustedPublicKey field in the source code.

The WPF/CAB Shell provides an options pane that allows users to view and action plugin changes, pictured below:
PluginPane.png
The plugin pane provides a list of all plugins, grouped by their basic type (implicitly trusted and untrusted) and sorted by name. Each plugin has its name, description, version and path displayed. Untrusted plugins have an additional item of information called status, which indicates whether the plugin is currently loaded or not.

In order to customize a plugin's name, description and version, you simply use assembly attributes. Please see the AssemblyInfo.cs for any of the plugins that come with the shell for an example.

WPF/CAB Shell includes a number of plugins, most of which are aimed at demonstrating the various services provided by the shell.

Services

WPF/CAB Shell provides a number of useful services that allow module developers to more quickly and effectively do their job. These services are discussed in this section, but you should always bear in mind that they may need to be supplemented or tailored according to the requirements of your application.

Command Service

The command service provides a means of obtaining an instance of WPFCABShell.Shell.Interface.Services.Command.ICommand. Instances of this type are used throughout the shell to represent commands. For example, when adding a tool bar item you will need an instance of this ICommand type.

CAB itself ships with command support, but it is limited compared to WPF's command support. Therefore, the shell provides its own abstraction over commands that encompasses both CAB and WPF commands. The command service allows you to easily wrap a CAB or WPF command in an instance of WPFCABShell.Shell.Interface.Services.Command.ICommand.

Once you have an ICommand instance, you can use it when creating menu items or tool bar items.

Menu Service

The menu service allows menu items to be added to menu extensibility points in the application, including the main menu and context menus. It does so in such a way that the caller has no dependency on the actual UI widgets in use. This means you could change the UI widgets being used by the shell without affecting any of your plugins.

One of the major features of the menu service is automatic grouping and sorting. When you add menu items with the menu service, you can optionally specify a group index and a regular index. Items in the same group are kept together, and are separated from other groups by instances of System.Windows.Controls.Separator. Within a group, the regular index (or, simply, index) is used to order the items. For example, the default Edit menu of the shell uses grouping and sorting to arrange its menu items:
EditMenu.png

Other intelligence is provided by the menu service. For example, a menu item that is not associated with a command is presumed to be a container for other menu items. Therefore, it is only visible if it has one or more visible child menu items.

Tool Bar Service

The tool bar service allows you to add tool bar items to either an existing or a new tool bar. If you add an item to a tool bar that does not yet exist, the service will automatically add the tool bar for you. Similarly, if you remove the last item from a tool bar, the service will automatically remove the tool bar itself.

The same grouping and sorting functionality provided with the menu service is also provided with the tool bar service. For example, the Edit tool bar uses grouping and sorting to arrange its tool bar items:
EditToolBar.png

In addition, the shell integrates menu support to allow users to show and hide tool bars:
ToolBarMenu.png

ToolBarContextMenu.png

Of course, this is all automatic from the perspective of the module developer. The module developer need only use the tool bar service and this functionality will be provided for free.

Status Bar Service

The status bar service mediates access to the application status bar, which is a piece of screen real estate that must be shared between many application components. It does this via a prioritization mechanism. Status bar operations are assigned one of three priorities when they are created:
  • Low
  • Normal (the default)
  • High

High priority messages trump normal priority, which trumps low priority. Operations of the same priority are ordered by creation time - newer operations trump older ones.

Status bar operations come in two basic varieties:
  • Message operations
  • Progress operations

The status bar provides three message operation locations:
  • Primary
  • Secondary
  • Ternary

The primary location supports text only, whilst the secondary and ternary support both text and images. An example of a primary message operation is the "Ready" text that is there by default:
StatusBarPrimary.png

An example of a secondary message operation is:
StatusBarSecondary.png

The other form of operations - progress operations - are just as simple to use as message operations. They can be used to show the progress of an application function. They can be determinate:
StatusBarDeterminateProgress.png

Or they can be indeterminate:
StatusBarIndeterminateProgress.png

Settings Service

The settings service provides a simple API that modules can use to hydrate and dehydrate simple user settings. For example, the Shortcuts plugin uses this service to persist information about the shortcuts set up by the user.

Options Service

The options service provides a means for plugins to add panes to the options window. In other words, the options window itself is extensible and dynamic. The code required to integrate with this window is minimal. Plugins need only provide a serializable data class (used to persist settings), and a view (a.k.a. pane) that allows users to edit those settings.

Skinning Service


The skinning service provides a means for skins to be registered with the shell, and allows users to switch between those skins. An example skin is included with the WPF/CAB Shell. As an example of the power of skinning, here is the Plugins options pane prior to skinning:
PluginPane.png

And here is that same pane after the user has selected the Bellucci skin:
PluginPaneBellucci.png

When a skin is registered via the skinning service, it is made available via the View/Skins menu:
ViewSkinsMenu.png

Visualizers

Visualizers are an important developer aid when building a CAB application. WPF/CAB Shell comes with visualizers that help developing an application that is based on it. You may need to modify the shell's App.config file to enable the visualizers.

Command Visualizer

The command visualizer is pictured below:
CommandVisualizer.png

It consists of two areas of information:
  • Registered commands
  • Command execution history

Registered commands are those commands that have been registered via the command service, as opposed to being created but not registered. Registered commands are commands that are likely to be useful for the user to access as shortcuts throughout the application. In the registered commands section, the command visualizer shows additional information about the command including an execution count and last execution time stamp.

The command execution history section shows a running list of command executions - both registered and unregistered commands. Each time a command is executed in the application, an entry will be added to this list.

Log Visualizer

The log visualizer is pictured below:
LogVisualizer.png

It consists of two sections
  • Logs
  • Log output

The logs section lists all available logs and allows you to choose what level of logging is desired for that log. The log output section shows all output from logs and is filtered according to the selected log level.

In order to have your log output appear in this visualizer, simply use the WPFCABShell.Shell.Interface.Diagnostics.Log class. For example:
public class MyClass
{
    private static readonly Log _log = Log.CreateForType(typeof(MyClass));

    public void Save()
    {
        _log.Verbose("Saving");
    }
}

Last edited Jan 6, 2008 at 4:29 PM by kentcb, version 6

Comments

No comments yet.