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:
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:
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.