Relations between Adorner, AdornerLayer and AdornerDecorator
I read this article about Adorner. I’d like to make a note to make some concepts more straightforward.
This is a base Adorner from which you will need to subclass.
The AdornerLayer can be considered as a plane in which the Adorners are drawn. 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. Anything placed in the adorner layer is rendered on top of the rest visual elements. In other words, adorners are always visually on top and cannot be overridden using z-order.
Defines the location of an AdornerLayer in visual tree . Window class already has it in the visual tree. It adds the default adorner layer above all other controls in the window.
The workflow is actually quite simple.
AdornerDecorator generates AdornerLayer at where it is in the visual tree. An AdornerDecorator can contain only one child, which is the parent element for the visual tree below the AdornerDecorator. AdornerDecorator divides a visual tree in two parallel branches one of which is the child of the AdornerDecorator with it’s visual subtree, and the other one is AdornerLayer, like the figure below.
Adorning a Single UIElement
To bind an adorner to a particular UIElement, follow these steps:
- Call the static method GetAdornerLayer of the AdornerLayer class 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 found. (If no adorner layers are found, the method returns null.)
- Create new instance of the adorner you need and pass it the instance of the UIElement you need to adorn.
- Call the Add method of the AdornerLayer, and pass it your newly created adorner to bind it to the target UIElement.
The following example binds SomeAdorner (our own Adorner) to a TextBox named myTextBox.
myAdornerLayer = AdornerLayer.GetAdornerLayer(myTextBox);
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 children of which are to be adorned.
2. Enumerate the children of the parent element and call the Add method to bind an adorner to each child element.
The following example binds a SomeAdorner (our own Adorne) to the children of a StackPanel named myStackPanel.
foreach (UIElement toAdorn in myStackPanel.Children)
Another thing worth of reminding is Validation.ErrorTemplate is rendered on AdornerLayer. So if you want your error template displayed, do not forget to give it a AdornerLayer, like what Karl does, or what Pavan does if you want your DnD works.
To quickly pick up Adorner, this article is probably a good start.
Update: although you can put an AdornerDecorator in XAML to let WPF itself create the AdornerLayer, you can also write code to do the job.
AdornerDecorator decorator = new AdornerDecorator();
decorator.Child = panel;
this.Content = decorator;
AdornerLayer layer = AdornerLayer.GetAdornerLayer(panel);