使用WPF创建画图箭头
2009-04-15 14:36
295 查看
今天要给leader line画个箭头,所以就google一下,找到下面的文章,写的不错,可以实现我的需求,所以就摘录下来。
我把源代码中的arraw.cs加入到我的工程,修改了namespace,然后写了个方法进行调用:
private void DrawLeaderLineArrow(Point startPt, Point endPt)
{
Arrowarrow = new Arrow();
arrow.X1 = startPt.X;
arrow.Y1 = startPt.Y;
arrow.X2 = endPt.X;
arrow.Y2 = endPt.Y;
arrow.HeadWidth = 15;
arrow.HeadHeight = 5;
arrow.Stroke= Brushes.Black;
arrow.StrokeThickness = 1;
_canvas.Children.Add(arrow);
}
WPF Arrowand Custom Shapes
Download source files - 41 KB
Well, surprisingly we can't base our custom shape on the
Don't worry! We still have an option to base our custom shape on the
Now, let’s say that we want to create an
Ooopps...
Never mind, let's derive directly from the
Our code should end up with something like this:
Collapse
Copy Code
As you can see, it is very easy to implement a custom shape, thanks to the great work in the
我把源代码中的arraw.cs加入到我的工程,修改了namespace,然后写了个方法进行调用:
private void DrawLeaderLineArrow(Point startPt, Point endPt)
{
Arrowarrow = new Arrow();
arrow.X1 = startPt.X;
arrow.Y1 = startPt.Y;
arrow.X2 = endPt.X;
arrow.Y2 = endPt.Y;
arrow.HeadWidth = 15;
arrow.HeadHeight = 5;
arrow.Stroke= Brushes.Black;
arrow.StrokeThickness = 1;
_canvas.Children.Add(arrow);
}
WPF Arrowand Custom Shapes
Download source files - 41 KB
Introduction
WPF is the best UI Framework ever. It provides us with a large arsenal of vector graphic types such asLine,
Ellipse,
Pathand others. Sometimes we need shapes which are not provided in the WPF arsenal (such an
Arrow), and with all due respect to the
Pathshape, which can be used to create any type of 2D shape, we do not want to recalculate each point every time. This is a good reason and opportunity to create a custom shape.
Background
WPF provides two kinds of vector types: Shapes and Geometries.Shapeis any type that derives from the
Shapebase class. It provides
Fill,
Strokeand other properties for coloring, and is actually a
FrameworkElement. Thus we can place shapes inside
Panels, we can register shapes routed events and do anything related to
FrameworkElement. (MSDN)
Geometryis any type that derives from the
Geometrybase type. It provides properties for describing any type of 2D geometry. A geometry is actually a
Freezabletype, thus can be frozen. A frozen object provides better performance by not notifying changes, and can be safely accessed by other threads.
Geometryis not
Visual, hence should be painted by other types such as
Path. (MSDN)
Using the Code
Now that we have a little background, and we know what the differences between aGeometryand
Shapeare, we can create our shape based on one of these two types. Correct?
Well, surprisingly we can't base our custom shape on the
Geometrytype, since its one and only default constructor is marked as internal. Shame on you Microsoft.
Don't worry! We still have an option to base our custom shape on the
Shapebase class.
Now, let’s say that we want to create an
Arrowshape. An arrow is actually a kind of line, so let’s derive our custom type from the WPF
Linetype which has
X1,
Y1,
X2and
Y2properties.
Ooopps...
Lineis sealed! (Shame on you twice).
Never mind, let's derive directly from the
Shapebase class, and add
X1,
Y1,
X2,
Y2and two additional properties for defining the arrow's head
widthand
height.
Our code should end up with something like this:
Collapse
Copy Code
public sealed class Arrow: Shape
{
public static readonly DependencyProperty X1Property = ...;
public static readonly DependencyProperty Y1Property = ...;
public static readonly DependencyProperty HeadHeightProperty = ...;
...
[TypeConverter(typeof(LengthConverter))]
public double X1
{
get { return (double)base.GetValue(X1Property); }
set { base.SetValue(X1Property, value); }
}
[TypeConverter(typeof(LengthConverter))]
public double Y1
{
get { return (double)base.GetValue(Y1Property); }
set { base.SetValue(Y1Property, value); }
}
[TypeConverter(typeof(LengthConverter))]
public double HeadHeight
{
get { return (double)base.GetValue(HeadHeightProperty); }
set { base.SetValue(HeadHeightProperty, value); }
}
...
protected override GeometryDefiningGeometry
{
get
{
// Create a StreamGeometryfor describing the shape
StreamGeometrygeometry = new StreamGeometry();
geometry.FillRule = FillRule.EvenOdd;
using (StreamGeometryContext context = geometry.Open())
{
InternalDrawArrowGeometry(context);
}
// Freeze the geometry for performance benefits
geometry.Freeze();
return geometry;
}
}
/// <summary>
/// Draws an Arrow
/// </summary>
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);
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, true, true);
context.LineTo(pt4, true, true);
}
}
As you can see, it is very easy to implement a custom shape, thanks to the great work in the
Shapebase class. All we have to do is derive our custom shape type from
Shape, and override the
DefiningGeometryproperty. This property should return a
Geometryof any type.
相关文章推荐
- Silverlight教程第八部分:使用WPF创建一个Digg桌面应用
- 使用WPF来创建 Metro UI
- 使用WPF创建无边框窗体
- C#中wpf使用Devexpress画图:柱状图,饼状图,散点图,曲线图
- 使用Visual Studio 2008创建WPF自定义按钮
- Silverlight教程第八部分:使用WPF创建一个Digg桌面应用
- 使用WPF创建一个Digg桌面应用
- WPF使用Page创建显示不同控件的程序
- F# 与 WPF 二 之使用纯后台代码创建WPF窗体
- 使用WPF创建SignalR服务端
- 使用Caliburn.Micro创建简单的WPF程序
- 只使用代码创建WPF应用程序
- Qt自定义控件的创建与初步使用(二)之图片上绘制文字、箭头、曲线
- 使用WPF创建炫亮按钮
- 使用OxyPlot在WPF中创建图表
- WPF中如何使用C#创建DataTemplate数据模版
- WPF 依赖属性的创建与使用
- Silverlight教程第八部分:使用WPF创建一个Digg桌面应用
- 技巧/诀窍: 创建和使用Silverlight和WPF 用户控件
- WPF中的柱形图的创建与使用