Adorner Architecture

The visual design experience requires adorners, which are special glyphs on the design surface. Adorners are usually attached to a target control, and they give the user a graphical means of adjusting the control's properties. For example, when you are designing a control, and you click a corner to resize it, the sizing glyph you click is an adorner.

The ability to draft, refine, and restyle adorners quickly and easily is important for the WPF Designer architecture. This overview explains how the WPF Designer adorner extensibility model makes it simple for you to create your own adorners for customizing the design experience for your controls.

The WPF Designer offers a flexible mechanism for displaying adorners. This mechanism is coupled with a flexible command system which allows adorners to respond to user input. You add adorners to a control by using the MetadataStore.

Types of Adorners

Adorners can model almost any visual design-time presentation, but some types of adorners appear repeatedly. The following table describes the commonly used adorners.

Adorner

Description

Grab handle

Enables moving and sizing a control; non-scaling.

Rail

Adds a marker or rule along one side of a control; non-scaling along a single axis.

Frame

Represents a control's bounds; scales along both axes.

Overlay

Captures mouse interactions in the region of the control; scales along both axes. Roughly equivalent to the Body Glyph in the System.ComponentModel designer framework.

Adorner Characteristics

The WPF Designer framework enables adorners which have the following characteristics.

  • Allow adorners to be derived from any UIElement class and to support Windows Presentation Foundation styles.

  • Allow for all size, position, and scaling to be specified independently for the horizontal and vertical dimensions.

  • Eliminate the need for an adorner base class. Adorner types may be derived from any UIElement type which meets your needs.

Creating Custom Adorners

Adorners are provided by the AdornerProvider feature provider. You can add an AdornerProvider feature to a class, which automatically adds adorners to the design surface. The following walkthroughs show you how to create custom adorners.

Adorner Extensibility

Adorners are added according to an adorner provider's policy. You add a policy to an AdornerProvider by adding the UsesItemPolicyAttribute to the class definition.

When the IsInPolicy check is satisfied, the adorner appears on the design surface.

You can add adorner providers to a control that offers adorners for a given policy. When the items in the policy change, the adorner feature connector queries for new adorner providers on new controls and displays an updated set of adorners.

The WPF Designer implements the PrimarySelectionAdornerProvider, which offers a set of adorners that are shown for the primary selection. Most custom adorner providers derive from this class.

Adorners and Layout

The most important issue for adorners is layout. Adorners require a wide variety of layout options. The specific stretching or scaling behavior for an adorner must be considered when the zoom setting is changed for the designer surface. Adorners must be able to size and position themselves according to the following schemes.

  • Relative to the applied style.

  • Relative to the adorned control’s size and position.

  • Relative to absolute pixel offsets.

  • Relative to the current zoom setting.

In WPF, the typical mechanism for controlling layout is the panel. The WPF Designer framework controls layout by using the AdornerPanel class to parent adorners for a given control on a design surface.

The AdornerPanel class offers methods which allow adorners to be sized and positioned relative to either the size specified by the adorner style, the size of the adorned control, or an absolute size in pixels. These methods are cumulative, which means you can create an adorner which is offset from a relative size or position. Such an offset can be set in logical pixels that either scale or do not scale when the zoom setting is changed for the designer surface. The AdornerPlacementCollection type provides methods for specifying these relationships.

The following code example shows how to position an adorner above the target control.

' Setup the adorner panel. 
' All adorners are placed in an AdornerPanel 
' for sizing and layout support. 
Dim myPanel = Me.Panel

AdornerPanel.SetHorizontalStretch(opacitySlider, AdornerStretch.Stretch)
AdornerPanel.SetVerticalStretch(opacitySlider, AdornerStretch.None)

Dim placement As New AdornerPlacementCollection()

' The adorner's width is relative to the content. 
' The slider extends the full width of the control it adorns.
placement.SizeRelativeToContentWidth(1.0, 0)

' The adorner's height is the same as the slider's.
placement.SizeRelativeToAdornerDesiredHeight(1.0, 0)

' Position the adorner above the control it adorns.
placement.PositionRelativeToAdornerHeight(-1.0, 0)

' Position the adorner up 5 pixels. This demonstrates  
' that these placement calls are additive. These two calls 
' are equivalent to the following single call: 
' PositionRelativeToAdornerHeight(-1.0, -5).
placement.PositionRelativeToAdornerHeight(0, -5)

AdornerPanel.SetPlacements(opacitySlider, placement)
// Setup the adorner panel. 
// All adorners are placed in an AdornerPanel 
// for sizing and layout support.
AdornerPanel myPanel = this.Panel;

AdornerPanel.SetHorizontalStretch(opacitySlider, AdornerStretch.Stretch);
AdornerPanel.SetVerticalStretch(opacitySlider, AdornerStretch.None);

AdornerPlacementCollection placement = new AdornerPlacementCollection();

// The adorner's width is relative to the content. 
// The slider extends the full width of the control it adorns.
placement.SizeRelativeToContentWidth(1.0, 0);

// The adorner's height is the same as the slider's.
placement.SizeRelativeToAdornerDesiredHeight(1.0, 0);

// Position the adorner above the control it adorns.
placement.PositionRelativeToAdornerHeight(-1.0, 0);

// Position the adorner up 5 pixels. This demonstrates  
// that these placement calls are additive. These two calls 
// are equivalent to the following single call: 
// PositionRelativeToAdornerHeight(-1.0, -5).
placement.PositionRelativeToAdornerHeight(0, -5);

AdornerPanel.SetPlacements(opacitySlider, placement);

Zooming Behavior

When the zoom setting for the designer view is changed to 200%, the adorned control is rendered at two times its size. All distances and fonts are larger, and lines are thicker. Many adorner designs specify that adorners remain their original size even when the designer view zoom changes.

Layout Space and Render Space

In the WPF Designer, you can place controls on the design surface relative to two different reference frames: layout space and render space.

Layout space defines how much space the control occupies when the layout of your design is calculated by the WPF layout system. Render space defines how much space a control occupies after the layout is calculated and all render transforms are applied. For more information, see Layout Space and Render Space.

DesignerView

The DesignerView class provides a collection of adorners and maps all user input to designer gestures. The DesignerView class derives from the Decorator class. It provides a visual surface for the designer. Assign the root element of the designer’s UI to the Child property of DesignerView and set the editing context property on the designer view to point to the editing context for the designer.

DesignerView view = new DesignerView();
view.Child = documentManager.View;
view.Context = editingContext;

The DesignerView class implements two aspects of the WPF Designer.

Adorners

The DesignerView class provides support for adorning elements in the view with additional visual adornments that overlay the controls being designed.

Input Routing

The DesignerView class routes user input to commands on adorners, tools, and tasks.

The DesignerView class works by introducing two additional elements in front of all content: an adorner layer and a hit-test layer. The following diagram shows the relationship of the designer view layers with the visual tree.

Designer View

The DesignerView class has an empty constructor for use in XAML.

See Also

Tasks

Walkthrough: Creating a Design-time Adorner

Reference

AdornerPanel

AdornerProvider

DesignerView

Other Resources

WPF Designer Extensibility