Udostępnij za pośrednictwem


WPF Designer Extensibility Architecture

The Windows Presentation Foundation (WPF) Designer for Visual Studio is a visual editing environment for WPF composite controls, which are implemented by the UserControl type. The WPF Designer is based on a framework with an extensible architecture, which you can extend to create your own custom design experience.

By extending the WPF Designer object model, you can customize the design-time appearance and behavior of WPF content to a remarkable degree. For example, you can extend the WPF Designer in the following ways:

  • Customize move and resize glyphs with enhanced graphics.

  • Add a glyph to the design surface which skews the selected control as the mouse moves.

  • Modify the design-time appearance and behavior of a control across different tools.

The WPF Designer architecture supports the full expressive power of WPF. This enables the creation of many visual design experiences which were not previously possible.

WPF Designer Object Model

The WPF Designer object model is modular, which means that when you extend the design time, you extend only the elements necessary for your features. You do not have to write a lot of supporting code to enable your custom design features. 

The object model consists of five functional units, which are described in the following table.

Functional unit

Description

Editing Model

Programming interface to objects in the designer.

Feature Providers

Main extensibility point in the designer framework.

Editing Context

Central store for a designer's state.

Tools

Tools to process user input.

Metadata Store

Store that contains the design-time behavior of a control to physically separates designer logic from runtime logic.

The following illustration shows the WPF Designer object model.

High-level object model

Note

The WPF Designer supports the full extensibility framework. Expression Blend supports only property editors, metadata loading, and licensing. Blend does not support menu actions and adorners. 

Editing Model

The design environment interacts with run-time controls though a programming interface called an editing model. The editing model consists of three functional subunits: a model, a public wrapper that abstracts the model, and a view that represents the user interface (UI) of the model.

The design environment uses the ModelItem type to communicate with the underlying model. All changes are made to the ModelItem wrappers, which affect the underlying model. This allows the model to be simple. The ModelItem wrappers handle complex designer features such as transaction support, undo tracking, and change notifications.

The ModelService class provides the entry point for the editing model and for global event notifications.

The ViewService class maps visual representations to the underlying model items.

Both services are required for the designer to function. The DesignerView class, which is responsible for processing user input and routing it to commands, requires both of these services to accurately map user input back to the model.

Feature Providers

You extend the design-time behavior of your types by using the FeatureProvider or the FeatureConnector<TFeatureProviderType> classes. The FeatureConnector<TFeatureProviderType> class manages a list of FeatureProvider objects.

The FeatureProvider class provides the most basic extensibility point. A feature provider is a lightweight feature or add-in which typically does not require much from the design environment and is created and destroyed in a given context. Features providers are used to add new bits of UI to the design surface or to modify some basic behavior. For example, a feature provider might add more grab handles or provide a new kind of mouse-drag behavior.

To access the deepest level of extensibility, derive from the FeatureConnector<TFeatureProviderType> class. This class exposes a service provider, through which derived feature connector classes can handle events and request and publish services. For example, you might implement a feature connector to provide selection UI or object-specific serialization.

In general, implement a feature to extend existing concepts. Implement a feature connector to provide new concepts. For more information, see Feature Providers and Feature Connectors.

Editing Context

A significant amount of state information is accumulated in a running designer. For example, your designer's state might include which objects are selected, or the behavior that occurs when the left mouse button is pressed. Designer state is stored in a central location, so that it can be found when it is needed. The EditingContext class represents this central repository of state for the designer.

The EditingContext class separates state into two categories: data and behavior. Data is stored as a table of context items and behavior is stored as a table of services. Both tables are indexed by a type-based key and are enumerable.

The ContextItem class holds a single piece of state in the designer. Context items are immutable, but new context items can replace existing context items to simulate mutability.

Services are accessed through a Services property, which returns an instance of ServiceManager, and context items are accessed through an Items property, which returns an instance of ContextItemManager.

Commands, Tasks, and Tools

The WPF Designer tool architecture consists of commands, tasks, and tools. 

A command is a unique identifier that represents some behavior. For example, "Cut" is a command which means to cut the current text and add it to the Clipboard. The code that implements "Cut" varies from application to application, and even varies within an application. For example, cutting text in a Word document is a different implementation than cutting text in the search text box of the same document. Regardless of implementation, the "Cut" command remains constant.

The WPF Designer augments the WPF command system by introducing a concept of a tool command. A tool command implements the ICommand interface and is like the RoutedCommand class.

A task has a collection of command bindings, which allows you to add routed commands. The DesignerView class has code which uses the same routing strategy as tool commands to find and execute routed commands that are defined on tasks. The DesignerView class enables tasks which support common WPF commands, such as Copy.

A tool is a class which processes user input. All user input comes into the designer as one or more input events. Those input events are passed to the currently active tool, which converts them to input bindings. If an input binding is returned, the command within the binding is executed.

A tool can represent the global mode of the designer. For example, if the user is selecting components on the design surface, that selection mode is possible because the currently active tool offers input bindings and commands that handle selection. When the user creates a new instance of a control, a different tool becomes active and offers a different set of commands, which are bound to the same input bindings.

Metadata Store

In the WPF Designer framework, metadata defining the design-time behavior of a control is factored into a separate assembly, that is called the metadata store. In the .NET Framework 3.5, the metadata store is implemented in code-based attribute tables, with an external XML file referring to designer code and a profile. Different tools can provide different metadata stores with completely different designer implementations. This decouples the run-time and design-time behavior, so that you can revise the designer separately from the control. For more information, see Metadata Store.

Designer Instance Creation

The following steps show how an example designer type might be instantiated by the WPF Designer environment. This fictitious example shows how a hypothetical designer might select a single button control on the design surface.

  1. The user invokes a tool-defined action requesting custom designer creation.

  2. The design environment enumerates an XML-based list of feature-to-type associations.

  3. The design environment adds custom metadata to these types by using the TypeDescriptor class. For example, a GrabHandleProvider could be associated with all UIElement types, including deriving types.

  4. An editing factory creates an editing store, a context, and a feature manager, and populates the editing store.

  5. The WPF Designer enumerates all UIElement objects, which are exposed by the editing store, and calls the InitializeFeatures method for each.

    1. Assume a Button element is declared in this hierarchy.

    2. The FeatureManager searches for a FeatureAttribute on the button. The FeatureManager discovers a FeatureAttribute on the button of type GrabHandleProvider.

    3. The FeatureManager continues to search the GrabHandleProvider type and discovers a FeatureConnectorAttribute associated with it. The FeatureConnectorAttribute specifies the SelectionConnector.

    4. The FeatureManager determines that this host does not yet exist. The FeatureManager creates the SelectionConnector and adds it to the list of active feature hosts.

    5. The SelectionConnector object starts monitoring the design surface for selection changes. The SelectionConnector object also obtains a reference to the adorner layer.

  6. The user changes the selection to the button, and the design-time tool raises a selection-changed event.

  7. The SelectionConnector receives this notification and creates all selection-based FeatureProvider instances associated with the selected object, including the GrabHandleProvider instance.

  8. The SelectionConnector queries the GrabHandleProvider for a list of adorners and adds them to the adorner layer. Grab handles appear around the selected button.

WPF Designer Assemblies

The WPF Designer consists of several assemblies which belong to one of three categories: public, private, and Visual Studio-specific.

The public assemblies expose classes which you can use to add design-time logic to your controls.

The private and Visual Studio-specific assemblies define the feature set of the WPF Designer and its interactions with Visual Studio. The following table shows how WPF Designer features are deployed.

Assembly

Public API

Description

Microsoft.VisualStudio.Xaml.dll

No

Visual Studio SDK integration logic

Microsoft.Windows.Design.Host.dll

Yes

Public API for hosting designer (specific to Visual Studio)

Microsoft.Windows.Design.Developer.dll

No

WPF Designer implementation. Only public API is an attribute table.

Microsoft.Windows.Design.Core.dll

Yes

Provides basic foundation for any designer through a service and data backplane and manipulation of metadata. This is the only assembly supported by Expression Blend.

Microsoft.Windows.Design.Extensibility.dll

Yes

Provides extensibility model through attributes.

Microsoft.Windows.Design.Interaction.dll

Yes

Provides user input and display classes.

Microsoft.Windows.Design.Markup.dll

Yes

Provides Extensible Application Markup Language (XAML) and document model mechanisms.

Note

Assemblies represent functionality boundaries, not namespace boundaries. You will often find namespaces which span than one assembly.

The WPF Designer and the Windows Forms Designer Architecture

The WPF Designer architecture is significantly different from the Windows Forms Designer architecture, which is characterized by the IComponent interface and the System.ComponentModel namespace. For more information, see Comparing the Windows Forms Designer Framework to the WPF Designer Framework

See Also

Concepts

Feature Providers and Feature Connectors

Other Resources

Developing Windows Forms Controls at Design Time

WPF Designer Extensibility