WPF Simplified Part 12: Adorners

An Adorner is a new WPF construct that helps us add visual features to a UIElement. The Adorner class derives directly from FrameworkElement. So, why would you need another class to add visual effects when you can pretty much customize any WPF control using control templates and data templates? The reason is that the adorner layer lies on top of the UI element in Z-order and is helpful in some interactive scenarios to display handles and outlines.

Creating an adorner is simple, consider a simple button,

    <Button Height="30" Width="110" x:Name="MyButton" Content="Adorned Button" />

and the code behind,

    public class MyAdorner : Adorner {
        public MyAdorner(UIElement targetElement) : base(targetElement) { }

        protected override void OnRender(DrawingContext drawingContext) {
            Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
            drawingContext.DrawRectangle(null, new Pen(Brushes.Blue, 1), adornedElementRect);
        }

    }

We have created a simple adorner that will create a border around an UIElement. The adorner constructor requires the target UIElement and will draw on top of this element. To hook up the adorner we need some more code,

    void Window1_Loaded(object sender, RoutedEventArgs e) {
        AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.MyTextBlock);
        MyAdorner myAdorner = new MyAdorner(this.MyTextBlock);
        adornerLayer.Add(myAdorner);
    }

Note that since the adorner layer is not available until the window is loaded, we’ve hooked up the code in the window’s Loaded event handler. GetAdornerLayer walks up the visual tree to find the first AdornerLayer which then can be used to render our custom adorner. The adorner layer’s location in the visual tree is determined by the AdornerDecorator element, the Window element provides an AdornerDecorator by default, which is what we added our custom adorner to. Note that this layer fills the entire window. If we want we can supply our own AdornerDecorator,

    <AdornerDecorator>
        <TextBlock x:Name="MyTextBlock" Text="Cancel" />
    </AdornerDecorator>

The adorner receives focus and input before the adorned UIElement. Also, just like we added the custom adorner to the AdornerLayer, we can remove it too, simply by,

    adornerLayer.Remove(myAdorner);

Another way to create Adorners is by providing a VisualCollection,

    public class MyAdorner : Adorner {
        // To store and manage the adorner's visual children
        VisualCollection visualChildren;

        // Custom UIElement to add to the target UIElement
        Button button = new Button();

        // Initialize the custom Adorner
        public MyAdorner(UIElement targetElement) : base(targetElement) {
            visualChildren = new VisualCollection(this);

            // Set the button properties
            button.Height = 20.0;
            button.Width = 20.0;
            button.Content = "?";

            visualChildren.Add(button);
        }

        protected override int VisualChildrenCount { get { return visualChildren.Count; } }
        protected override Visual GetVisualChild(int index) { return visualChildren[index]; }

        // Arrange the Adorner
        protected override Size ArrangeOverride(Size finalSize) {
            double desiredWidth = AdornedElement.DesiredSize.Width;
            double desiredHeight = AdornedElement.DesiredSize.Height;

            button.Arrange(new Rect((button.Width + desiredWidth) / 2, -desiredHeight, 
                                 desiredWidth, desiredHeight));
            return finalSize;
        }
    }

Combined with this xaml,

    <Grid>
        <Button Height="30" Width="110" x:Name="MyButton" Content="Adorned Button" />
    </Grid>

should render,

image

Digg This
Advertisements

About soumya chattopadhyay
I live and work in Seattle, WA. I work with Microsoft technologies, and I'm especially interested in C#.

4 Responses to WPF Simplified Part 12: Adorners

  1. Pingback: WPF Simplified Series « I.Net

  2. Hi Soumya,

    I have a question about adorner which is pretty new to me. I have a canvas on which i have added some items(Labels); When ever i click on the items, i need to draw a selection adorner or when i drag it, i need to create a dragable adorner. Can you please give me some tips?

  3. obama sucks nigger dick says:

    this article suck sthe nigger dick
    who is the shit sob cock sucker who posted this price of crapola aticle

  4. Pingback: Fix Wpf Error Adorner Windows XP, Vista, 7, 8 [Solved]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: