Click here to Skip to main content
15,062,966 members
Articles / Desktop Programming / WPF
Posted 25 Jan 2010

Tagged as


179 bookmarked

Defining WPF Adorners in XAML

Rate me:
Please Sign up or sign in to vote.
4.97/5 (87 votes)
15 Mar 2011CPOL7 min read
Examines a custom class that allows adorners to be defined in XAML.


This article explains a technique that I have used to define WPF adorners in XAML. The technique requires two custom classes.

These classes are used to define:

  • the control to be adorned; and
  • the UI elements that make up the adorner

The main class is AdornedControl which is derived from ContentControl. The content of AdornedControl is displayed in the normal way in the visual tree of the UI. The adorner is defined using the AdornerContent property of AdornedControl. The content of this property, in XAML, defines the UI elements that will be placed in the adorner that is attached to the AdornedControl.

I have included two sample projects to accompany this article. The simple sample shows a very simple use of AdornedControl that is described in this article. The advanced sample shows a more advanced usage that meets the needs described in the Background section below.

Assumed Knowledge

It is assumed that you already know C# and have a basic knowledge of using WPF and XAML. Knowledge of the WPF visual and logical tree will also be helpful.


Recently, I found that I was in need of a way to display auxiliary controls when the user hovers the mouse over a particular control.

The particular control is a flow-chart node embedded in a Canvas that looks like this:


The purpose of the auxiliary controls was for the user to be able to drag the node around the Canvas and also to be able to remove the node from the Canvas.

This is what the node looks like with the auxiliary controls displayed:


Normally, the auxiliary controls will not be displayed. They will only be visible when the mouse has moved over the node. They will remain visible until the mouse has moved away from the node and a period of time has elapsed. I decided that adorners would fit this situation well because they are defined outside of the node's visual tree and therefore will not interfere with the normal layout and visuals of the node.

The usual way of creating adorners and adding them to the adorner layer is accomplished through procedural code. What I really wanted was to design both the adorned controls and their adorners in XAML. I created two custom classes that work together to allow this: AdornedControl and FrameworkElementAdorner.

But first let's review the usual way of working with adorners.

Using Adorners - The Usual Way

The normal method of using adorners is procedural. You need to create a class that derives from Adorner. In the derived class, you either have some custom rendering code or you attach UI elements and visuals as children to the adorner. Next, you create an instance of your derived adorner class. The UI element that is to be adorned is passed into the constructor of the adorner. Lastly, the adorner is added to the adorner layer. All this is achieved procedurally in C# code.

To illustrate, here is a simple example.

Firstly, here is the class derived from adorner:

class MyAdorner : Adorner
    public MyAdorner(UIElement adornedElement) :
        // ... other initialisation ...

    // ... class members ...

Custom rendering code is added to 'OnRender' where you can use 'drawingContext' directly:

protected override void OnRender(DrawingContext drawingContext)

	// ... add custom rendering code here ...

When you are ready to display the adorner and allow the user to interact with it must be added to the adorner layer. AdornerLayer.GetAdornerLayer is called and typically passed a reference to the UI element that is to be adorned. GetAdornerLayer searches back up the visual tree for an appropriate adorner layer to use.

Control parentControl = ...
	UIElement adornedElement = ...
	AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(parentControl);
	MyAdorner myAdorner = new MyAdorner(adornedElement);

The alternative to writing custom rendering code is to add children to the visual tree of the adorner. This means that any class derived from Visual can be instanced and added to the visual tree underneath the adorner. I have used this technique in FrameworkElementAdorner.

This has only been a brief discussion about using adorners procedurally. The main purpose of my article is to discuss how to use adorners defined in XAML.

Defining Adorners in XAML using AdornedControl

There are many advantages to defining the UI in XAML. Not only is it simpler than writing the equivalent procedural code, but it's also safer and less prone to errors. Unfortunately, as shown above, adorners are usually created procedurally and cannot, by default, be defined in XAML. This seems like an unnecessary omission from WPF and so I implemented a class that allows it.

AdornedControl allows adorners to be defined in XAML. It defines both the adorner and the control that is to be adorned.

This is the most basic definition of an AdornedControl in XAML:

>>	<local:AdornedControl
>>		Width="50"
>>		Height="50"
>>		>
>>	</local:AdornedControl>

AdornedControl derives from ContentControl. As such it can wrap any other content, visual or UI element. For example, this defines the UI element to be adorned as a rectangle:

>>		<Rectangle
>>			Stroke="Blue"
>>			/>

The next example defines an ellipse as the adorner for the rectangle:

>>		<local:AdornedControl.AdornerContent>
>>			<Ellipse
>>				Width="50"
>>				Height="50"
>>				Stroke="Green"
>>				/>
>>		</local:AdornedControl.AdornerContent>

Now we use AdornedControl's HorizontalAdornerPlacement combined with the adorner's HorizontalAlignment to place the adorner horizontally, and outside the adorned control on the right.

>>		HorizontalAdornerPlacement="Outside"
>>				HorizontalAlignment="Right"

AdornedControl has various ways of showing and hiding the adorner but here we use the IsAdornerVisible property to make it visible by default:

>>	        IsAdornerVisible="True"

IsAdornerVisible can also be set procedurally to show or hide the adorner. Alternatively the Show() and Hide() functions and Show and Hide commands can be used. In the advanced sample, I use animation to fade the adorner in and out when it is shown and hidden.

Finally, the other custom class which I haven't yet mentioned is FrameworkElementAdorner. This class is used internally by AdornedControl. It derives from Adorner and references a FrameworkElement as its child in the visual tree. This is what allows us to add any FrameworkElement into the visual tree of the adorner.

FrameworkElementAdorner is based on UIElementAdorner by Josh Smith which can be found here. I adapted it to work with FrameworkElement and made a few modifications that I needed. The code for FrameworkElementAdorner is a good example of how to create an adorner that has visual children.


This example has explained how to use AdornedControl to define, in XAML, an adorned control and its adorner.


  • 7th February, 2010: Article updated
    • The SizeChanged of the adorned element is now monitored in order to update the placement of the adorner
    • Fixed issue with placement of the adorner on the outside top & left of the adorned element
  • 27th February, 2010: Code updated
    • The update is simply to remove the copyright information from Assembly.cs that was automatically added when the project was generated. I tested that the code still compiles and runs.
  • 18th June, 2010: Article updated
    • The 'Focusable' property for AdornedControl is now set to 'false' by default.
    • Added a new improved sample project. Functionally the 'improved sample' is the same as the 'advanced sample', however the animation code to fade in and fade out the adorner is now integrated into the AdornedControl class itself which makes it trivial to move this functionality to new projects. The new methods 'FadeInAdorner' and 'FadeOutAdorner' can be called to fade the adorner in and out. Alternately the 'FadeIn' and 'FadeOut' commands can trigger this behaviour. The new property 'IsMouseOverShowEnabled' can be set to 'true' to automatically fade in and show the adorner when the mouse cursor is hovered over the adorned control.
  • 25th September, 2010: Article updated
    • The animation state of the adorner is now set when showing/hiding the adorner by setting the IsAdornerVisible property (thanks to Tri Q Tran for pointing this out)
    • Made some changes to make sure the animation state of the adorner is always correct
    • Opacity is now animated on the adorner rather than the adorner content
  • 11th October, 2010: Article updated
    • Added a new dependency property to AdornedControl. AdornedTemplatePartName is used to specify the part name of an element in the visual-tree that is to be adorned. By default, the property is set to null which causes the AdornedControl itself to be the UI element that is adorned (the original behaviour). When the property is set to a valid part name, AdornedControl searches the visual-tree below itself to find the named UI element that is to be adorned. For example, when AdornerContent is an editable ComboBox setting AdornedTemplatePartName to PART_EditableTextBox will cause the TextBox part of the ComboBox to be adorned.
      This feature was requested by Richard Deeming.
  • 15th March, 2011: Article updated
    • Fixed an issue in ImprovedAdornedControlSample. This issue was reported by Member 2477019 (see article messages for details) and the fix was proposed by Louis-Philippe Lauzier.
    • I removed the code in HideAdornerInternal that was setting IsAdornerVisible to false. This line of code appears to be interfering with data-binding, and after analysis, this line of code appears totally unnecessary, so removing it should cause no issues.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Ashley Davis
Chief Technology Officer Sortal
Australia Australia
My new book, Bootstrapping Microservices, is a practical and project-based guide to building distributed applications with microservices:

My first book, Data Wrangling with JavaScript, is a comprehensive overview of working with data in JavaScript:

Data-Forge Notebook is my notebook-style application for data transformation, analysis and visualizatiion in JavaScript:

I have a long history in software development with many years in apps, web apps, serious games, sims and VR. Making technology work for business is what I do: building bespoke software solutions that span multiple platforms.

I have years of experience managing teams, preparing technical strategies and creation of software products. I can explain complicated technology to senior management. I have delivered cutting-edge products in fast-paced and high-pressure environments. I know how to focus and prioritize to get the important things done.

I am a passionate technologist and agile practitioner. I have had great success with TDD and am convinced of its ability to produce better code that stabilizes more quickly while being evolved rapidly. I'm a fan of functional programming and its potential for safety, predictability & concurrency.

I contribute to open source and have founded multiple industry groups.

I'm also a keen systems trader, currently trading stocks on the ASX.

Creator of Market Wizard:

Creator of Data-Forge and Data-Forge Notebook:


Open source



Management of teams & projects
Making sense of technology for senior management
Developing technical strategies
Data wrangling & visualiz

Comments and Discussions

GeneralRe: visibility of adorner for itemlist Pin
AuroreC1-Dec-11 21:49
MemberAuroreC1-Dec-11 21:49 
QuestionMultiple Adorners per Adorned Element ? [modified] Pin
Hussein Khalil19-Sep-11 13:18
MemberHussein Khalil19-Sep-11 13:18 
AnswerRe: Multiple Adorners per Adorned Element ? Pin
Ashley Davis19-Sep-11 14:02
MemberAshley Davis19-Sep-11 14:02 
GeneralRe: Multiple Adorners per Adorned Element ? Pin
Hussein Khalil20-Sep-11 5:18
MemberHussein Khalil20-Sep-11 5:18 
GeneralRe: Multiple Adorners per Adorned Element ? Pin
Ashley Davis20-Sep-11 13:12
MemberAshley Davis20-Sep-11 13:12 
QuestionGreat work - but how about rotation? Pin
Cleric Stormgate9-Aug-11 22:49
MemberCleric Stormgate9-Aug-11 22:49 
AnswerRe: Great work - but how about rotation? Pin
Ashley Davis10-Aug-11 21:22
MemberAshley Davis10-Aug-11 21:22 
AnswerRe: Great work - but how about rotation? Pin
Ashley Davis10-Aug-11 21:25
MemberAshley Davis10-Aug-11 21:25 
Oh... one tip: if you are trying to experiment with adorners and rotation you should probably take my code out of the equation. I'd recommend just working with the raw adorners so that you know my code isn't interfering with your rotation code. Once you know how to get rotation working you could then integrate it back into my code if you wanted to.
GeneralMy vote of 5 Pin
Filip D'haene23-Jun-11 8:17
MemberFilip D'haene23-Jun-11 8:17 
GeneralBugs in ImprovedAdornerSample Pin
Exertive5-May-11 2:39
professionalExertive5-May-11 2:39 
GeneralRe: Bugs in ImprovedAdornerSample Pin
Ashley Davis7-May-11 1:55
MemberAshley Davis7-May-11 1:55 
QuestionBinding Data to UserControl used as AdornedContent Pin
Ryan Borchert16-Apr-11 13:52
professionalRyan Borchert16-Apr-11 13:52 
AnswerRe: Binding Data to UserControl used as AdornedContent Pin
Ashley Davis9-May-11 5:22
MemberAshley Davis9-May-11 5:22 
AnswerRe: Binding Data to UserControl used as AdornedContent Pin
AuroreC19-Dec-11 5:07
MemberAuroreC19-Dec-11 5:07 
GeneralRe: Binding Data to UserControl used as AdornedContent Pin
Ashley Davis19-Dec-11 13:07
MemberAshley Davis19-Dec-11 13:07 
GeneralRe: Binding Data to UserControl used as AdornedContent Pin
AuroreC19-Dec-11 20:42
MemberAuroreC19-Dec-11 20:42 
GeneralRe: Binding Data to UserControl used as AdornedContent Pin
acutus1-Aug-12 21:26
Memberacutus1-Aug-12 21:26 
GeneralMy vote of 5 Pin
Espen Harlinn15-Mar-11 13:26
mvaEspen Harlinn15-Mar-11 13:26 
GeneralProblems with IsAdornerVisible Pin
Member 24770194-Feb-11 14:34
MemberMember 24770194-Feb-11 14:34 
GeneralRe: Problems with IsAdornerVisible Pin
Ashley Davis7-Feb-11 1:41
MemberAshley Davis7-Feb-11 1:41 
GeneralRe: Problems with IsAdornerVisible Pin
Ashley Davis11-Feb-11 2:50
MemberAshley Davis11-Feb-11 2:50 
AnswerRe: Problems with IsAdornerVisible Pin
Louis-Philippe Lauzier10-Mar-11 3:36
MemberLouis-Philippe Lauzier10-Mar-11 3:36 
GeneralRe: Problems with IsAdornerVisible Pin
Ashley Davis10-Mar-11 3:38
MemberAshley Davis10-Mar-11 3:38 
GeneralRe: Problems with IsAdornerVisible Pin
Ashley Davis14-Mar-11 5:14
MemberAshley Davis14-Mar-11 5:14 
GeneralRe: Problems with IsAdornerVisible Pin
Sean A. Hanley25-May-11 10:27
MemberSean A. Hanley25-May-11 10:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.