using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace CustomControls
{
[TypeDescriptionProvider(typeof(CustomTypeDescriptionProvider))]
public class CustomArrow : Shape
{
public CustomArrow ()
{
Stroke= new SolidColorBrush(Color.FromRgb(0, 140, 206));
}
#region Dependency Properties
public static readonly DependencyProperty X1Property = DependencyProperty.Register("X1", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty Y1Property = DependencyProperty.Register("Y1", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty X2Property = DependencyProperty.Register("X2", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(150.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty Y2Property = DependencyProperty.Register("Y2", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty HeadWidthProperty = DependencyProperty.Register("HeadWidth", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(15.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty HeadHeightProperty = DependencyProperty.Register("HeadHeight", typeof(double), typeof(BvArrow), new FrameworkPropertyMetadata(5.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
public static readonly DependencyProperty IsBidirectionalProperty = DependencyProperty.Register("IsBidirectional", typeof(bool), typeof(BvArrow), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
#endregion
#region CLR Properties
[Browsable(true)]
public bool IsBidirectional
{
get
{
return (bool)GetValue(IsBidirectionalProperty);
}
set
{
SetValue(IsBidirectionalProperty, value);
}
}
[Browsable(true)]
public new Brush Stroke
{
get
{
return (Brush)GetValue(StrokeProperty);
}
set
{
SetValue(StrokeProperty, value);
}
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public new double StrokeThickness
{
get
{
return (double)GetValue(StrokeThicknessProperty);
}
set
{
SetValue(StrokeThicknessProperty, value);
}
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double X1
{
get { return (double)base.GetValue(X1Property); }
set { base.SetValue(X1Property, value); }
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double Y1
{
get { return (double)base.GetValue(Y1Property); }
set { base.SetValue(Y1Property, value); }
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double X2
{
get { return (double)base.GetValue(X2Property); }
set { base.SetValue(X2Property, value); }
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double Y2
{
get { return (double)base.GetValue(Y2Property); }
set { base.SetValue(Y2Property, value); }
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double HeadWidth
{
get { return (double)base.GetValue(HeadWidthProperty); }
set { base.SetValue(HeadWidthProperty, value); }
}
[Browsable(true)]
[TypeConverter(typeof(LengthConverter))]
public double HeadHeight
{
get { return (double)base.GetValue(HeadHeightProperty); }
set { base.SetValue(HeadHeightProperty, value); }
}
#endregion
#region Overrides
protected override Geometry DefiningGeometry
{
get
{
// Create a StreamGeometry for describing the shape
StreamGeometry geometry = new StreamGeometry();
geometry.FillRule = FillRule.EvenOdd;
using (StreamGeometryContext context = geometry.Open())
{
InternalDrawArrowGeometry(context);
}
// Freeze the geometry for performance benefits
geometry.Freeze();
return geometry;
}
}
#endregion
#region Privates
private void InternalDrawArrowGeometry(StreamGeometryContext context)
{
double theta = Math.Atan2(Y1 - Y2, X1 - X2);
double sint = Math.Sin(theta);
double cost = Math.Cos(theta);
Point pt1 = new Point(X1, this.Y1);
Point pt2 = new Point(X2, this.Y2);
if(IsBidirectional)
{
Point pt3 = new Point(
X1 - (HeadWidth * cost - HeadHeight * sint),
Y1 - (HeadWidth * sint + HeadHeight * cost));
Point pt4 = new Point(
X1 - (HeadWidth * cost + HeadHeight * sint),
Y1 + (HeadHeight * cost - HeadWidth * sint));
Point pt5 = new Point(
X2 + (HeadWidth * cost - HeadHeight * sint),
Y2 + (HeadWidth * sint + HeadHeight * cost));
Point pt6 = new Point(
X2 + (HeadWidth * cost + HeadHeight * sint),
Y2 - (HeadHeight * cost - HeadWidth * sint));
context.BeginFigure(pt1, true, false);
context.LineTo(pt3, true, true);
context.LineTo(pt1, false, true);
context.LineTo(pt4, false, true);
context.LineTo(pt1, true, true);
context.LineTo(pt2, true, true);
context.LineTo(pt5, true, true);
context.LineTo(pt2, false, true);
context.LineTo(pt6, true, true);
}
else
{
Point pt3 = new Point(
X2 + (HeadWidth * cost - HeadHeight * sint),
Y2 + (HeadWidth * sint + HeadHeight * cost));
Point pt4 = new Point(
X2 + (HeadWidth * cost + HeadHeight * sint),
Y2 - (HeadHeight * cost - HeadWidth * sint));
context.BeginFigure(pt1, true, false);
context.LineTo(pt2, true, true);
context.LineTo(pt3, true, true);
context.LineTo(pt2, false, true);
context.LineTo(pt4, true, true);
}
}
#endregion
}
}