When should I use adorners?

WPF is great because there are many ways to achieve your goals. For example, from what I understand, adorners can add some controls to a UI element, but I think that the same behavior can be achieved through a custom control that contains the additional element.

So, my question is: when should I prefer adorners to a more complex (but I think, more flexible) custom control? Please consider that I'm extensively using MVVM pattern and I would like to bind commands to the additional element.

In particular, I'm designing a diagram designer application and I would like to add connection points to my shapes. Another example where I should decide between a custom control and an adorner is a line which shows a label automatically positioned to "follow" the line.

Thank you


Solution 1:

Adorners require a little more work than using ControlTemplates for most purposes. If you want the additional functionality that adorners provide, use them. Otherwise use ControlTemplates.

Here are the main features that Adorners bring to the table:

  1. Because adorners are on a separate layer, the visual can extend beyond the adorned element, even if the adorned element is clipped.
  2. Because adorners are on a separate layer, they are generally not obscured by the AdornedElement's container or by sibling controls.
  3. Adorners are automatically notified of all changes in the size and location of the adorned element, allowing responses to layout changes that are not as easily achieved with ordinary controls.
  4. Adorners can be applied to panels and to existing controls without making any changes to their templates or otherwise. This makes them good for providing manipulation handles or visual feedback on arbitrary controls.
  5. In many scenarios you will create adorners only for a few "active" items out of hundreds or thousands. Implementing the same functionality using ControlTemplates can be dramatically less efficient if you have to add an additional Panel to the template: Every single instatiation of the template will have the extra panel, whereas there would be just one adorner.

Here are some of the potential costs associated with using adorners as opposed to ControlTemplates:

  1. You must write code to call .GetAdornerLayer() and .Add() and to manage the lifetime of the Adorner
  2. You must either write rendering code for your Adorner or add code to include a Control as a child of the adorner so you can use a ControlTemplate with it
  3. You'll generally do your custom measure/arrange calculations in code (unless you are using a ControlTemplate within your adorner)
  4. You'll need to forward RoutedEvents to the AdornedElement if you want them to be handled by the target control
  5. You'll need to add a DataContext="{Binding AdornedElement.DataContext}" if you want to bring the DataContext across
  6. It appears that visible Adorner is scanned on every layout pass, so having many thousands of adorners onscreen at once can result in noticeable slowdowns. (Ordinary visuals only have their measure/arrange code called when something that directly affects them changes.)
  7. Having more than 144 adorners is not supported, so control templates are more suitable if there's any risk of getting close to this limit.

In your particular examples, there are no clear-cut right answers.

  • I'd lean toward using a ControlTemplate for connection points since you will presumably need a way to specify the locations of the connection points, and the ControlTemplate is already defining the layout the item itself. On the other hand, if the connection point information is data-driven and only appears on the active control (or the control being dragged over) it might be better to use adorners to get the performance advantages and simplify the individual ControlTemplates.

  • An automatically positioned label could be a good fit for an adorner from a measure/arrange calculation point of view if the lines are anything but simple straight lines, but if you will potentially have ten thousand of these visible at once I would be concerned about performance.

Without knowing more about your application it is hard to say more than this.