WPF Designer Extensibility Architecture
The WPF Designer for Visual Studio is a visual editing environment for WPF and Silverlight elements. 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 framework, you can customize the design-time appearance and behavior of WPF and Silverlight 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 shortcut menu to the design surface which changes the state of a control.
Modify the design-time appearance and behavior of a control across different tools.
The WPF Designer architecture supports the full expressive power of WPF and Silverlight. This enables the creation of many visual design experiences which were not previously possible.
For an example of how to implement a custom design-time experience for WPF and Visual Studio, see Walkthrough: Creating a Design-time Adorner.
For sample code that shows how to create custom design experiences for WPF and Silverlight, see the WPF Designer Extensibility Samples site.
The WPF Designer framework 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 |
|---|---|
|
Programming interface to objects in the designer. |
|
|
Main extensibility point in the designer framework. |
|
|
Central store for a designer's state. |
|
|
Commands, tasks, and tools to process user input. |
|
|
Assemblies that contain the design-time behavior of a control, to physically separate designer logic from run-time logic. |
The following illustration shows the functional units of the WPF Designer framework.
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 the Services property, which returns an instance of ServiceManager, and context items are accessed through the 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.
Design-time Metadata
In the WPF Designer framework, metadata defining the design-time behavior of a control is specified by attributes and factored into a separate assembly. Different designers can consume different metadata assemblies with completely different design-time implementations. This decouples the run-time and design-time behavior, so that you can revise the designer separately from the control.
To specify an assembly that provides design-time implementation, mark the assembly with the ProvideMetadataAttribute and include a class that implements the IProvideAttributeTable interface.
For more information, see Providing Design-time Metadata.
The WPF Designer supports all features in the extensibility framework. Expression Blend supports the following features.
-
Adorners
-
Context menus
-
Default initializers
-
All of the ModelItem features, such as selection and manipulation
-
Properties window extensibility
Expression Blend does not support ParentAdapter and PlacementAdapter.
The WPF Designer consists of several assemblies which belong to one of three categories: public, private, and designer-specific.
The public assemblies expose classes which you can use to add design-time logic to your controls.
The private and designer-specific assemblies define the feature set of the WPF Designer and its interactions with designers, such as Visual Studio and Expression Blend.
The WPF and Silverlight designers are installed as a single entity. There is not a separate package for each designer.
The following table shows how WPF Designer features are deployed.
|
Assembly |
Public API |
Description |
|---|---|---|
|
Microsoft.Windows.Design.Extensibility.dll |
Yes |
Provides an extensibility model through attributes and Visual Studio SDK integration logic. |
|
Microsoft.Windows.Design.Interaction.dll |
Yes |
Provides user input and display classes. |
|
Microsoft.Windows.Design.Markup.dll |
No |
Provides XAML and document model mechanisms. |
|
Microsoft.VisualStudio.Xaml.dll |
No |
Provides basic XAML foundation for any designer through a service, a data backplane, and manipulation of metadata. |
|
Microsoft.Windows.Design.Host.dll |
No |
Private API for hosting a designer (specific to Visual Studio). |
|
Microsoft.Windows.Design.Developer.dll |
No |
WPF Designer implementation. |
|
Microsoft.Windows.Design.Developer.WPF.dll |
No |
|
|
Microsoft.Windows.Design.Developer.Silverlight.dll |
No |
|
|
Microsoft.Windows.Design.Platform.dll |
No |
Platform layer with abstract classes. Platform implementations implement abstract classes in this assembly. |
|
Microsoft.Windows.Design.Platform.WPF.dll |
No |
Platform-specific design-time for WPF. |
|
Microsoft.Windows.Design.Platform.Silverlight.dll |
No |
Platform-specific design-time for Silverlight. |
|
Microsoft.Expression.DesignModel.dll |
No |
Expression Blend design-time assembly. |
|
Microsoft.Expression.Platform.WPF.dll |
No |
Expression Blend design-time assembly. |
|
Microsoft.Expression.Platform.Silverlight.dll |
No |
Expression Blend design-time assembly. |
Note
|
|---|
|
Assemblies represent functionality boundaries, not namespace boundaries. You will often find namespaces that span more than one assembly. |
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.
You can browse the whole entire .NET Class Framework library, class-by-class, property-by-property on MSDN, such as System.Windows.Controls. But, when it comes to authoring design-time experiences for custom controls, all that is provided is obtuse documentation and examplels and no way to browse framework-level documentation on assmblies such as Microsoft.Windows.Design.*.dll assemblies.
It makes one wonder if this information is only privy to the likes of Infragistics, Telerik, Component One, and Dundas, et. al. If you're not an employee of one of these companies, then you have to struggle through ILDASM and try to make sense of the internals of what's going on? I thought MS was all about Developers, Developers, Developers! But without this kind of information, we're relegated to only creating apps, and not becoming enablers for others to create apps through our own custom control development.
I sure hope that in the future MS will allow developers to develop for every aspect of their platform and not make things like design-time experiences for custom control developers (outside the big 4 I mentioned above) nearly impossible to achieve.
- 12/23/2011
- fourpastmidnight
Note