334 lines
10 KiB
C#
334 lines
10 KiB
C#
//
|
|
// This code based on code available here:
|
|
//
|
|
// http://www.codeproject.com/KB/WPF/WPFJoshSmith.aspx
|
|
//
|
|
namespace VideoBrowser.Controls.AdornedControl
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Windows;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Media;
|
|
|
|
//
|
|
// This class is an adorner that allows a FrameworkElement derived class to adorn another FrameworkElement.
|
|
//
|
|
public class FrameworkElementAdorner : Adorner
|
|
{
|
|
//
|
|
// The framework element that is the adorner.
|
|
//
|
|
private FrameworkElement child;
|
|
|
|
//
|
|
// Placement of the child.
|
|
//
|
|
private readonly AdornerPlacement horizontalAdornerPlacement = AdornerPlacement.Inside;
|
|
|
|
private readonly AdornerPlacement verticalAdornerPlacement = AdornerPlacement.Inside;
|
|
|
|
//
|
|
// Offset of the child.
|
|
//
|
|
private readonly double offsetX = 0.0;
|
|
|
|
private readonly double offsetY = 0.0;
|
|
|
|
//
|
|
// Position of the child (when not set to NaN).
|
|
//
|
|
private double positionX = Double.NaN;
|
|
|
|
private double positionY = Double.NaN;
|
|
|
|
public FrameworkElementAdorner(FrameworkElement adornerChildElement, FrameworkElement adornedElement)
|
|
: base(adornedElement)
|
|
{
|
|
this.child = adornerChildElement;
|
|
|
|
base.AddLogicalChild(adornerChildElement);
|
|
base.AddVisualChild(adornerChildElement);
|
|
}
|
|
|
|
public FrameworkElementAdorner(FrameworkElement adornerChildElement, FrameworkElement adornedElement,
|
|
AdornerPlacement horizontalAdornerPlacement, AdornerPlacement verticalAdornerPlacement,
|
|
double offsetX, double offsetY)
|
|
: base(adornedElement)
|
|
{
|
|
this.child = adornerChildElement;
|
|
this.horizontalAdornerPlacement = horizontalAdornerPlacement;
|
|
this.verticalAdornerPlacement = verticalAdornerPlacement;
|
|
this.offsetX = offsetX;
|
|
this.offsetY = offsetY;
|
|
|
|
adornedElement.SizeChanged += new SizeChangedEventHandler(adornedElement_SizeChanged);
|
|
|
|
base.AddLogicalChild(adornerChildElement);
|
|
base.AddVisualChild(adornerChildElement);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event raised when the adorned control's size has changed.
|
|
/// </summary>
|
|
private void adornedElement_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
{
|
|
InvalidateMeasure();
|
|
}
|
|
|
|
//
|
|
// Position of the child (when not set to NaN).
|
|
//
|
|
public double PositionX
|
|
{
|
|
get
|
|
{
|
|
return positionX;
|
|
}
|
|
set
|
|
{
|
|
positionX = value;
|
|
}
|
|
}
|
|
|
|
public double PositionY
|
|
{
|
|
get
|
|
{
|
|
return positionY;
|
|
}
|
|
set
|
|
{
|
|
positionY = value;
|
|
}
|
|
}
|
|
|
|
protected override Size MeasureOverride(Size constraint)
|
|
{
|
|
this.child.Measure(constraint);
|
|
return this.child.DesiredSize;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the X coordinate of the child.
|
|
/// </summary>
|
|
private double DetermineX()
|
|
{
|
|
switch (child.HorizontalAlignment)
|
|
{
|
|
case HorizontalAlignment.Left:
|
|
{
|
|
if (horizontalAdornerPlacement == AdornerPlacement.Outside)
|
|
{
|
|
return -child.DesiredSize.Width + offsetX;
|
|
}
|
|
else
|
|
{
|
|
return offsetX;
|
|
}
|
|
}
|
|
case HorizontalAlignment.Right:
|
|
{
|
|
if (horizontalAdornerPlacement == AdornerPlacement.Outside)
|
|
{
|
|
double adornedWidth = AdornedElement.ActualWidth;
|
|
return adornedWidth + offsetX;
|
|
}
|
|
else
|
|
{
|
|
double adornerWidth = this.child.DesiredSize.Width;
|
|
double adornedWidth = AdornedElement.ActualWidth;
|
|
double x = adornedWidth - adornerWidth;
|
|
return x + offsetX;
|
|
}
|
|
}
|
|
case HorizontalAlignment.Center:
|
|
{
|
|
double adornerWidth = this.child.DesiredSize.Width;
|
|
double adornedWidth = AdornedElement.ActualWidth;
|
|
double x = (adornedWidth / 2) - (adornerWidth / 2);
|
|
return x + offsetX;
|
|
}
|
|
case HorizontalAlignment.Stretch:
|
|
{
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the Y coordinate of the child.
|
|
/// </summary>
|
|
private double DetermineY()
|
|
{
|
|
switch (child.VerticalAlignment)
|
|
{
|
|
case VerticalAlignment.Top:
|
|
{
|
|
if (verticalAdornerPlacement == AdornerPlacement.Outside)
|
|
{
|
|
return -child.DesiredSize.Height + offsetY;
|
|
}
|
|
else
|
|
{
|
|
return offsetY;
|
|
}
|
|
}
|
|
case VerticalAlignment.Bottom:
|
|
{
|
|
if (verticalAdornerPlacement == AdornerPlacement.Outside)
|
|
{
|
|
double adornedHeight = AdornedElement.ActualHeight;
|
|
return adornedHeight + offsetY;
|
|
}
|
|
else
|
|
{
|
|
double adornerHeight = this.child.DesiredSize.Height;
|
|
double adornedHeight = AdornedElement.ActualHeight;
|
|
double x = adornedHeight - adornerHeight;
|
|
return x + offsetY;
|
|
}
|
|
}
|
|
case VerticalAlignment.Center:
|
|
{
|
|
double adornerHeight = this.child.DesiredSize.Height;
|
|
double adornedHeight = AdornedElement.ActualHeight;
|
|
double x = (adornedHeight / 2) - (adornerHeight / 2);
|
|
return x + offsetY;
|
|
}
|
|
case VerticalAlignment.Stretch:
|
|
{
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the width of the child.
|
|
/// </summary>
|
|
private double DetermineWidth()
|
|
{
|
|
if (!Double.IsNaN(PositionX))
|
|
{
|
|
return this.child.DesiredSize.Width;
|
|
}
|
|
|
|
switch (child.HorizontalAlignment)
|
|
{
|
|
case HorizontalAlignment.Left:
|
|
{
|
|
return this.child.DesiredSize.Width;
|
|
}
|
|
case HorizontalAlignment.Right:
|
|
{
|
|
return this.child.DesiredSize.Width;
|
|
}
|
|
case HorizontalAlignment.Center:
|
|
{
|
|
return this.child.DesiredSize.Width;
|
|
}
|
|
case HorizontalAlignment.Stretch:
|
|
{
|
|
return AdornedElement.ActualWidth;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine the height of the child.
|
|
/// </summary>
|
|
private double DetermineHeight()
|
|
{
|
|
if (!Double.IsNaN(PositionY))
|
|
{
|
|
return this.child.DesiredSize.Height;
|
|
}
|
|
|
|
switch (child.VerticalAlignment)
|
|
{
|
|
case VerticalAlignment.Top:
|
|
{
|
|
return this.child.DesiredSize.Height;
|
|
}
|
|
case VerticalAlignment.Bottom:
|
|
{
|
|
return this.child.DesiredSize.Height;
|
|
}
|
|
case VerticalAlignment.Center:
|
|
{
|
|
return this.child.DesiredSize.Height;
|
|
}
|
|
case VerticalAlignment.Stretch:
|
|
{
|
|
return AdornedElement.ActualHeight;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|
{
|
|
double x = PositionX;
|
|
if (Double.IsNaN(x))
|
|
{
|
|
x = DetermineX();
|
|
}
|
|
double y = PositionY;
|
|
if (Double.IsNaN(y))
|
|
{
|
|
y = DetermineY();
|
|
}
|
|
double adornerWidth = DetermineWidth();
|
|
double adornerHeight = DetermineHeight();
|
|
this.child.Arrange(new Rect(x, y, adornerWidth, adornerHeight));
|
|
return finalSize;
|
|
}
|
|
|
|
protected override Int32 VisualChildrenCount
|
|
{
|
|
get { return 1; }
|
|
}
|
|
|
|
protected override Visual GetVisualChild(Int32 index)
|
|
{
|
|
return this.child;
|
|
}
|
|
|
|
protected override IEnumerator LogicalChildren
|
|
{
|
|
get
|
|
{
|
|
ArrayList list = new ArrayList();
|
|
list.Add(this.child);
|
|
return list.GetEnumerator();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Disconnect the child element from the visual tree so that it may be reused later.
|
|
/// </summary>
|
|
public void DisconnectChild()
|
|
{
|
|
base.RemoveLogicalChild(child);
|
|
base.RemoveVisualChild(child);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override AdornedElement from base class for less type-checking.
|
|
/// </summary>
|
|
public new FrameworkElement AdornedElement
|
|
{
|
|
get
|
|
{
|
|
return (FrameworkElement)base.AdornedElement;
|
|
}
|
|
}
|
|
}
|
|
} |