As I have mentioned at the end of the previous post today I will show you how to create a generic adorner, which will allow you to decorate a single element  multiple times at different positions. At the end we will be able to create something that looks like this:

TopicWithAdorners

To achieve this we will need a way to say that we want to position the adorner at the different corners of the element as well as to specify whether we want to be inside or outside (vertically or horizontally) of the element. Let's create some enumeration types that will serve for this purpose. Introducing AdornerPosition and AdornerPlacement enums.

AdornerPosition

public enum AdornerPosition

{

    Unspecified = 0,

    TopLeft = 1,

    TopCenter = 2,

    TopRight = 3,

    MiddleLeft = 4,

    MiddleCenter = 5,

    MiddleRight = 6,

    BottomLeft = 7,

    BottomCenter = 8,

    BottomRight = 9

}

AdornerPlacement

public enum AdornerPlacement

{

    Unspecified = 0,

    In = 1,

    OutHorizontally = 2,

    OutVertically = 3

}

Each of the enums' values speak for it self, but for clarity here is a diagram that illustrates them:

  AdornerPlacementAndPosition

The final piece is to implement the ArrangeOverride() method of the Adorner class. It looks like this:

protected override Size ArrangeOverride( Size finalSize )

{

    if ( adorningElement != null )

    {

        Point adorningPoint = new Point();

        int pos = (int) position - 1;

 

        Rect adorneredElementRect = VisualTreeHelper.GetContentBounds( AdornedElement );

        Rect adorningElementRect = VisualTreeHelper.GetContentBounds( adorningElement );

 

        adorningPoint.X = ( ( ( pos % 3 ) / 2d ) * adorneredElementRect.Width )

                          - ( ( ( pos % 3 ) / 2d ) * adorningElementRect.Width );

        adorningPoint.Y = ( ( ( pos / 3 ) / 2d ) * adorneredElementRect.Height )

                          - ( ( ( pos / 3 ) / 2d ) * adorningElementRect.Height );

        if ( placement == AdornerPlacement.OutHorizontally )

        {

            switch ( pos % 3 )

            {

                default :

                case 1 :

                {

                    //center column do nothing

                    break;

                }

                case 0 :

                {

                    adorningPoint.X -= adorningElementRect.Width;

                    break;

                }

                case 2 :

                {

                    adorningPoint.X += adorningElementRect.Width;

                    break;

                }

            }

        }

        else if ( placement == AdornerPlacement.OutVertically )

        {

            switch ( pos / 3 )

            {

                default :

                case 1 :

                {

                    //center row do nothing

                    break;

                }

                case 0 :

                {

                    adorningPoint.Y -= adorningElementRect.Height;

                    break;

                }

                case 2 :

                {

                    adorningPoint.Y += adorningElementRect.Height;

                    break;

                }

            }

        }

 

        adorningElement.Arrange( new Rect( adorningPoint, adorningElement.DesiredSize ) );

    }

    return finalSize;

}

That's it. You can now adorn your elements passing different positions and placements. Sample project can be downloaded from here.

Have fun adorning your elements.


Related Posts

Comments