Project archive #1 Project archive #2 Project archive #3 Project archive #4
In WPF, an Adorner is special FrameworkElement that can be bounded to UIElement to allow user manipulate that element. Under manipulating we mean:
WPF does not provide concrete adorners but it does provide the basic infrastructure. That means that you need to write your own special Adorner class. A base infrastructure consists of next classes:
To bind an adorner to a particular UIElement, follow these steps:
The following example binds SomeAdorner (our own Adorner) to a TextBox named myTextBox.
myAdornerLayer = AdornerLayer.GetAdornerLayer(myTextBox); myAdornerLayer.Add(new SomeAdorner(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) myAdornerLayer.Add(new SomeAdorner(toAdorn));
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 adorner is independent of rendering UIElement the adorner is bound to. An adorner is typically positioned relatively to the element to which it is bound, using the standard 2-D coordinate origin located at the upper-left of the adorned element. 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.
It is important to note that adorners do not include any inherent rendering behavior (by default Adorner class does not render anything), ensuring that an adorner's rendering is the responsibility of the adorner's implementer.
This means that the adorner's rendering should be implemented by:
The following examples accordingly show these approaches.
The first example adorner simply adorns the corners of a UIElement with circles.
The following image shows the SimpleCircleAdorner applied to a TextBox.
Sources of example above.
Second approach:
An example above is simplified. Complete version is here.
As I mentioned above, there is another class that plays an important role in rendering, called AdornerDecorator. AdornerDecorator determines a placement of AdornerLayer in the visual tree. That 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.
For better understanding we will consider the next example. Let us create a new project. First of all lets implement our own Adorner class.
As you have already seen we used HyperContol class as a child of our Adorner. This class is also used to represent Adorner. Here its implementation:
After above implementations we must create generic.xaml resource file where ControlTemplate and Style for HyperControl should be created.
Create GUI of our project in Window1.xaml.
Implement code-behind file.
Run that project and start dragging TextBlock with Text property set to "Test". You can see that adorner can be draged above the entire Window.
You can get that project here.
After that lets change Window1.xaml by adding AdornerDecorator in the Grid. And sets its ClipToBounds property to true:
Run that, and you will notice that adorner can be dragged only inside the grid element.
Source files of the project can be found here.
So, I hope that after that experience you will understand the purpose of AdornerDecorator class.
Note: If you need to switch adorner layer and adorned element in z-order, you should derrive from AdornerDecorator class and override GetVisualChild method (it's default implementation can be discovered using the awesome tool by Lutz Roeder's, named Reflector).
Adorners receive input events just like any other FrameworkElement. As the adorner always has a higher z-order than the element it adorns, the adorner receives input events 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.