Adorners Overview

Adorners are a special type of FrameworkElement, used to provide visual cues to a user. Among other uses, Adorners can be used to add functional handles to elements or provide state information about a control.

About Adorners

An Adorner is a custom FrameworkElement that is bound to a UIElement. Adorners are rendered in an AdornerLayer, which is a rendering surface that is always on top of the adorned element or a collection of adorned elements. Rendering of an adorner is independent from rendering of the UIElement that the adorner is bound to. An adorner is typically positioned relative to the element to which it is bound, using the standard 2D coordinate origin located at the upper-left of the adorned element.

Common applications for adorners include:

  • Adding functional handles to a UIElement that enable a user to manipulate the element in some way (resize, rotate, reposition, etc.).
  • Provide visual feedback to indicate various states, or in response to various events.
  • Overlay visual decorations on a UIElement.
  • Visually mask or override part or all of a UIElement.

Windows Presentation Foundation (WPF) provides a basic framework for adorning visual elements. The following table lists the primary types used when adorning objects, and their purpose. Several usage examples follow:

Class Description
Adorner An abstract base class from which all concrete adorner implementations inherit.
AdornerLayer A class representing a rendering layer for the adorner(s) of one or more adorned elements.
AdornerDecorator A class that enables an adorner layer to be associated with a collection of elements.

Implementing a Custom Adorner

The adorners framework provided by Windows Presentation Foundation (WPF) is intended primarily to support the creation of custom adorners. A custom adorner is created by implementing a class that inherits from the abstract Adorner class.

Note

The parent of an Adorner is the AdornerLayer that renders the Adorner, not the element being adorned.

The following example shows a class that implements a simple adorner. The example adorner simply adorns the corners of a UIElement with circles.

// Adorners must subclass the abstract base class Adorner.
public class SimpleCircleAdorner : Adorner
{
  // Be sure to call the base class constructor.
  public SimpleCircleAdorner(UIElement adornedElement)
    : base(adornedElement)
  {
  }

  // A common way to implement an adorner's rendering behavior is to override the OnRender
  // method, which is called by the layout system as part of a rendering pass.
  protected override void OnRender(DrawingContext drawingContext)
  {
    Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);

    // Some arbitrary drawing implements.
    SolidColorBrush renderBrush = new SolidColorBrush(Colors.Green);
    renderBrush.Opacity = 0.2;
    Pen renderPen = new Pen(new SolidColorBrush(Colors.Navy), 1.5);
    double renderRadius = 5.0;

    // Draw a circle at each corner.
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius);
  }
}
Public Class SimpleCircleAdorner
    Inherits Adorner
    Sub New(ByVal adornedElement As UIElement)
        MyBase.New(adornedElement)
    End Sub

    Protected Overrides Sub OnRender(ByVal drawingContext As System.Windows.Media.DrawingContext)
        MyBase.OnRender(drawingContext)
        Dim adornedElementRect As New Rect(AdornedElement.DesiredSize)
        Dim renderBrush As New SolidColorBrush(Colors.Green)
        renderBrush.Opacity = 0.2
        Dim renderPen As New Pen(New SolidColorBrush(Colors.Navy), 1.5)
        Dim renderRadius As Double
        renderRadius = 5.0

        'Draw a circle at each corner.
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius)
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius)
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius)
        drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius)
    End Sub
End Class

The following image shows the SimpleCircleAdorner applied to a TextBox:

Screenshot that shows an adorned text box.

Rendering Behavior for Adorners

It is important to note that adorners do not include any inherent rendering behavior; ensuring that an adorner renders is the responsibility of the adorner implementer. A common way of implementing rendering behavior is to override the OnRender method and use one or more DrawingContext objects to render the adorner's visuals as needed (as shown in the example above).

Note

Anything placed in the adorner layer is rendered on top of the rest of any styles you have set. In other words, adorners are always visually on top and cannot be overridden using z-order.

Events and Hit Testing

Adorners receive input events just like any other FrameworkElement. Because an adorner always has a higher z-order than the element it adorns, the adorner receives input events (such as Drop or MouseMove) that may be intended for the underlying adorned element. An adorner can listen for certain input events and pass these on to the underlying adorned element by re-raising the event.

To enable pass-through hit testing of elements under an adorner, set the hit test IsHitTestVisible property to false on the adorner. For more information about hit testing, see Hit Testing in the Visual Layer.

Adorning a Single UIElement

To bind an adorner to a particular UIElement, follow these steps:

  1. Call the static method GetAdornerLayer to get an AdornerLayer object for the UIElement to be adorned. GetAdornerLayer walks up the visual tree, starting at the specified UIElement, and returns the first adorner layer it finds. (If no adorner layers are found, the method returns null.)

  2. Call the Add method to bind the adorner to the target UIElement.

The following example binds a SimpleCircleAdorner (shown above) to a TextBox named myTextBox:

myAdornerLayer = AdornerLayer.GetAdornerLayer(myTextBox);
myAdornerLayer.Add(new SimpleCircleAdorner(myTextBox));
myAdornerLayer = AdornerLayer.GetAdornerLayer(myTextBox)
myAdornerLayer.Add(New SimpleCircleAdorner(myTextBox))

Note

Using Extensible Application Markup Language (XAML) to bind an adorner to another element is currently not supported.

Adorning the Children of a Panel

To bind an adorner to the children of a Panel, follow these steps:

  1. Call the static method GetAdornerLayer to find an adorner layer for the element whose children are to be adorned.

  2. Enumerate through the children of the parent element and call the Add method to bind an adorner to each child element.

The following example binds a SimpleCircleAdorner (shown above) to the children of a StackPanel named myStackPanel:

foreach (UIElement toAdorn in myStackPanel.Children)
  myAdornerLayer.Add(new SimpleCircleAdorner(toAdorn));
For Each toAdorn As UIElement In myStackPanel.Children
    myAdornerLayer.Add(New SimpleCircleAdorner(toAdorn))
Next

See also