我需要在画布中的控件之间绘制一个箭头。目前我正在使用Line
对象,但它没有办法在该行的末尾绘制一个三角形。
这大致是我需要的:
[TextBox] <----- [Button]
我试图将Line
子类化,并在最后添加几行但该类已被密封。
如何构建一个在X1,Y1和X2,Y2之间绘制箭头的自定义控件?
答案 0 :(得分:7)
Charles Petzold写了一个用于在WPF中执行此操作的库。至少逻辑应该转移到Silverlight。它使用折线和路径,并且应该易于移植。
Lines with Arrows @ Petzold Book Blog
<强> - 编辑 - 强>
好的 - 这是另一种方法:
创建用户控件:
<UserControl x:Class="ArrowsAndDaggersLibrary.ArrowsAndDaggersUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas x:Name="LayoutRoot">
<Line x:Name="Cap" />
<Line x:Name="Connector" />
<Line x:Name="Foot" />
</Canvas>
</UserControl>
使用以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ArrowsAndDaggersLibrary
{
public partial class ArrowsAndDaggersUC : UserControl
{
private Point startPoint;
public Point StartPoint
{
get { return startPoint; }
set
{
startPoint = value;
Update();
}
}
private Point endPoint;
public Point EndPoint
{
get { return endPoint; }
set {
endPoint = value;
Update();
}
}
public ArrowsAndDaggersUC()
{
InitializeComponent();
}
public ArrowsAndDaggersUC(Point StartPoint, Point EndPoint)
{
InitializeComponent();
startPoint = StartPoint;
endPoint = EndPoint;
Update();
}
private void Update()
{
//reconfig
Connector.X1 = startPoint.X;
Connector.Y1 = startPoint.Y;
Connector.X2 = endPoint.X;
Connector.Y2 = endPoint.Y;
Connector.StrokeThickness = 1;
Connector.Stroke = new SolidColorBrush(Colors.Black);
Cap.X1 = startPoint.X;
Cap.Y1 = startPoint.Y;
Cap.X2 = startPoint.X;
Cap.Y2 = startPoint.Y;
Cap.StrokeStartLineCap = PenLineCap.Triangle;
Cap.StrokeThickness = 20;
Cap.Stroke = new SolidColorBrush(Colors.Black);
Foot.X1 = endPoint.X;
Foot.Y1 = endPoint.Y;
Foot.X2 = endPoint.X;
Foot.Y2 = endPoint.Y;
Foot.StrokeEndLineCap = PenLineCap.Triangle;
Foot.StrokeThickness = 20;
Foot.Stroke = new SolidColorBrush(Colors.Black);
}
}
}
这样称呼:
LayoutRoot.Children.Add(new ArrowsAndDaggersUC(new Point(200, 200), new Point(300, 400)));
你将在每行末尾有1px笔划线和20px笔划三角形。
<强> - 编辑 - 强>
@ Number8有一个关于如何修改用户控件的问题,以便大写字母指向与该行相同的方向。
修改用户控件的Xaml,如下所示:
<UserControl x:Class="ArrowsAndDaggersLibrary.ArrowsAndDaggersUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas x:Name="LayoutRoot">
<Line x:Name="Cap">
<Line.RenderTransform>
<RotateTransform x:Name="CapRotateTransform" />
</Line.RenderTransform>
</Line>
<Line x:Name="Connector" />
<Line x:Name="Foot">
<Line.RenderTransform>
<RotateTransform x:Name="FootRotateTransform" />
</Line.RenderTransform>
</Line>
</Canvas>
</UserControl>
然后,更改“更新”方法以获取线条的角度并将大写字母旋转到该角度:
private void Update()
{
double angleOfLine = Math.Atan2((endPoint.Y - startPoint.Y), (endPoint.X - startPoint.X)) * 180 / Math.PI;
Connector.X1 = startPoint.X;
Connector.Y1 = startPoint.Y;
Connector.X2 = endPoint.X;
Connector.Y2 = endPoint.Y;
Connector.StrokeThickness = 1;
Connector.Stroke = new SolidColorBrush(Colors.Black);
Cap.X1 = startPoint.X;
Cap.Y1 = startPoint.Y;
Cap.X2 = startPoint.X;
Cap.Y2 = startPoint.Y;
Cap.StrokeStartLineCap = PenLineCap.Triangle;
Cap.StrokeThickness = 20;
Cap.Stroke = new SolidColorBrush(Colors.Black);
CapRotateTransform.Angle = angleOfLine;
CapRotateTransform.CenterX = startPoint.X;
CapRotateTransform.CenterY = startPoint.Y;
Foot.X1 = endPoint.X;
Foot.Y1 = endPoint.Y;
Foot.X2 = endPoint.X;
Foot.Y2 = endPoint.Y;
Foot.StrokeEndLineCap = PenLineCap.Triangle;
Foot.StrokeThickness = 20;
Foot.Stroke = new SolidColorBrush(Colors.Black);
FootRotateTransform.Angle = angleOfLine;
FootRotateTransform.CenterX = endPoint.X;
FootRotateTransform.CenterY = endPoint.Y;
}
答案 1 :(得分:5)
这个简单的方法也会创建一个箭头,它对我有用。
private static Shape DrawArrow(Point p1, Point p2)
{
GeometryGroup lineGroup = new GeometryGroup();
double theta = Math.Atan2((p2.Y - p1.Y),(p2.X - p1.X)) * 180 / Math.PI;
PathGeometry pathGeometry = new PathGeometry();
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = p1;
Point lpoint = new Point(p1.X + 2, p1.Y + 10);
Point rpoint = new Point(p1.X - 2, p1.Y + 10);
LineSegment seg1 = new LineSegment();
seg1.Point = lpoint;
pathFigure.Segments.Add(seg1);
LineSegment seg2 = new LineSegment();
seg2.Point = rpoint;
pathFigure.Segments.Add(seg2);
LineSegment seg3 = new LineSegment();
seg3.Point = p1;
pathFigure.Segments.Add(seg3);
pathGeometry.Figures.Add(pathFigure);
RotateTransform transform = new RotateTransform();
transform.Angle = theta - 90;
transform.CenterX = p1.X;
transform.CenterY = p1.Y;
pathGeometry.Transform = transform;
lineGroup.Children.Add(pathGeometry);
LineGeometry connectorGeometry = new LineGeometry();
connectorGeometry.StartPoint = p1;
connectorGeometry.EndPoint = p2;
lineGroup.Children.Add(connectorGeometry);
Path path = new Path();
path.Data = lineGroup;
return path;
}
答案 2 :(得分:0)
您可以尝试使用三角形笔帽;我用它来做类似的事情
http://msdn.microsoft.com/en-us/library/system.windows.media.penlinecap(VS.95).aspx
答案 3 :(得分:0)
所有这些运行时和动画线
//animation
public class Cls_Barriere
{
// animazione periferica
public static void LineAnimation(Line _line,String _colore)
{
Storyboard result = new Storyboard();
Duration duration = new Duration(TimeSpan.FromSeconds(2));
ColorAnimation animation = new ColorAnimation();
animation.RepeatBehavior = RepeatBehavior.Forever;
animation.Duration = duration;
switch (_colore.ToUpper())
{
case "RED":
animation.From = Colors.Red;
break;
case "ORANGE":
animation.From = Colors.Orange;
break;
case "YELLOW":
animation.From = Colors.Yellow;
break;
case "GRAY":
animation.From = Colors.DarkGray;
break;
default:
animation.From = Colors.Green;
break;
}
animation.To = Colors.Gray;
Storyboard.SetTarget(animation, _line);
Storyboard.SetTargetProperty(animation, new PropertyPath("(Line.Stroke).(SolidColorBrush.Color)"));
result.Children.Add(animation);
result.Begin();
}
}
public partial class MainPage : UserControl
{
private Point startPoint;
private Point endPoint;
// canvas event onmouse click to start drawing runtime a line
public MainPage()
{
InitializeComponent();
Canvas.MouseLeftButtonDown += Canvas_MouseLeftButtonDown;
Canvas.MouseLeftButtonUp += Canvas_MouseLeftButtonUp;
}
// on muose up drawing line and add canvas all references
void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
endPoint = new Point();
endPoint.X = e.GetPosition(this.Canvas).X;
endPoint.Y = e.GetPosition(this.Canvas).Y;
Line LineCap = new Line();
Line LineFoot = new Line();
Line LineConnect = new Line();
RotateTransform FootRotateTransform = new RotateTransform();
RotateTransform CapRotateTransform = new RotateTransform();
LineConnect.Stroke = new SolidColorBrush(Colors.White);
LineConnect.StrokeThickness = 5;
LineConnect.StrokeStartLineCap = PenLineCap.Round;
LineConnect.StrokeEndLineCap = PenLineCap.Round;
LineConnect.X1 = startPoint.X;
LineConnect.Y1 = startPoint.Y;
LineConnect.X2 = endPoint.X;
LineConnect.Y2 = endPoint.Y;
LineCap.X1 = startPoint.X;
LineCap.X2 = startPoint.X;
LineCap.Y1 = startPoint.Y;
LineCap.Y2 = startPoint.Y;
LineCap.StrokeThickness = 20;
LineCap.StrokeStartLineCap = PenLineCap.Round;
LineCap.Stroke = new SolidColorBrush(Colors.White);
LineFoot.StrokeThickness = 20;
LineFoot.X1 = endPoint.X;
LineFoot.X2 = endPoint.X;
LineFoot.Y1 = endPoint.Y;
LineFoot.Y2 = endPoint.Y;
LineFoot.StrokeEndLineCap = PenLineCap.Triangle;
LineFoot.Stroke = new SolidColorBrush(Colors.White);
Double angleOfLine = new Double();
angleOfLine = Math.Atan2((LineConnect.Y2 - LineConnect.Y1), (LineConnect.X2 - LineConnect.X1)) * 180 / Math.PI;
FootRotateTransform.Angle = angleOfLine;
FootRotateTransform.CenterX = endPoint.X;
FootRotateTransform.CenterY = endPoint.Y;
CapRotateTransform.Angle = angleOfLine;
CapRotateTransform.CenterX = startPoint.X;
CapRotateTransform.CenterY = startPoint.Y;
LineFoot.RenderTransform = FootRotateTransform;
LineCap.RenderTransform = CapRotateTransform;
LineConnect.Loaded += _line_Loaded;
LineCap.Loaded += _line_Loaded;
LineFoot.Loaded += _line_Loaded;
Canvas.Children.Add(LineConnect);
Canvas.Children.Add(LineCap);
Canvas.Children.Add(LineFoot);
}
//load animation color
void _line_Loaded(object sender, RoutedEventArgs e)
{
Cls_Barriere.LineAnimation(sender as Line, "RED");
}
// add canvas lines
void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = new Point();
startPoint.X = e.GetPosition(this.Canvas).X;
startPoint.Y = e.GetPosition(this.Canvas).Y;
}
}