WPF中的形状Shape与几何图形Geometry详解
WPF中的形状Shape与几何图形Geometry详解
总目录
文章目录
一、Shape(形状)
1、Shape基本信息
Shape 是一种 UIElement,可让你在屏幕上绘制形状。
由上可知:可用的形状对象包括 Ellipse、Line、Path、Polygon、Polyline 和 Rectangle 都是派生自Shape,另外Shape 对象共享以下公共的属性:
- Stroke:描述形状边框的绘制方式。
- StrokeThickness:描述形状边框的粗细。
- Fill:描述形状内部的绘制方式。
- Stretch :定如何拉伸 Shape 对象的内容(要绘制的形状)以填充 Shape 对象的布局空间
- 用于指定坐标和顶点的数据属性,以与设备无关的像素来度量。
由于它们是 UI 元素,因此可在 Panel 元素和大多数控件中使用 Shape 对象。由于 Canvas 面板支持其子对象的绝对位置,因此特别适合创建复杂的图形。另外辅以ViewBox的使用,则可以自动缩放创建的图形!
下面案例则是通过Canvas 和Shape创建的复杂图形:
<Canvas Height="30" Width="200" Margin="0,10,0,0">
<Border CornerRadius="15" Width="200" Height="30" BorderThickness="1" BorderBrush="Red"></Border>
<Ellipse Height="20" Width="20" Fill="Red" Canvas.Top="5" Canvas.Left="10"></Ellipse>
<Ellipse Height="20" Width="20" Fill="Red" Canvas.Top="5" Canvas.Left="50"></Ellipse>
<Ellipse Height="20" Width="20" Fill="Red" Canvas.Top="5" Canvas.Left="90"></Ellipse>
<Ellipse Height="20" Width="20" Fill="Red" Canvas.Top="5" Canvas.Left="130"></Ellipse>
<Ellipse Height="20" Width="20" Fill="Red" Canvas.Top="5" Canvas.Left="170"></Ellipse>
<Border Height="1" Background="Red" Width="180" Canvas.Top="15" Canvas.Left="10"></Border>
</Canvas>
2、Ellipse
1、案例
代码如下(示例):
<StackPanel Orientation="Horizontal">
<Ellipse Height="70" Width="70" Margin="10" Stroke="White" StrokeThickness="5" >
<Ellipse.Fill>
<ImageBrush ImageSource="/MvvmDemo;component/Res/Images/lg.png"/>
</Ellipse.Fill>
</Ellipse>
<Ellipse Height="70" Width="70" Margin="10" Stroke="White" StrokeThickness="5" Fill="Gray"/>
<Ellipse Height="70" Width="70" Margin="10" Stroke="Red" StrokeThickness="1" StrokeDashArray="3">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFB6FBCF" Offset="0"/>
<GradientStop Color="#FF36950A" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Height="70" Width="100" Margin="10" Stroke="White" StrokeThickness="5" Fill="Gray"/>
</StackPanel>
效果如下:
2、说明
由上面案例我们可总结以下知识点:
- Stroke 可以设置Ellipse的边框颜色,通常我们可以通过设置Stroke 做一个 用户图像 的展示控件,如上案例所示。
- 当我们需要椭圆形的时候,只需设置不同的宽高即可。
StrokeDashArray
属性 可以设置边框的形式,如设置成虚线。- 通过Fill 我们可以给Ellipse 填充 各种色彩以及图片
3、Rectangle
1、案例
<Rectangle Height="20" Width="150" Fill="Red" RadiusX="10" RadiusY="10"/>
2、说明
- Shape公共的属性,这里就不多介绍了
- Rectangle 的RadiusX 和 RadiusY 属性是设置方形的圆角
4、Line
Line用于绘制直线
1、案例
<UniformGrid Height="400" Width="200" Background="White" Rows="15" >
<Line X1="10" Y1="10" X2="180" Y2="10" Stroke="Black" StrokeThickness="3"></Line>
<Line X1="10" Y1="10" X2="180" Y2="25" StrokeDashArray="2" Stroke="Black" StrokeThickness="3"></Line>
<Line X1="10" Y1="10" X2="180" Y2="10" StrokeStartLineCap="Square" StrokeEndLineCap="Round" Stroke="BlueViolet" StrokeThickness="3"></Line>
<Line X1="10" Y1="10" X2="180" Y2="10" StrokeDashCap="Round" StrokeDashArray="2" Stroke="Red" StrokeThickness="3"></Line>
<Line X1="10" Y1="10" X2="180" Y2="10" StrokeDashCap="Triangle" StrokeDashArray="4" Stroke="Red" StrokeThickness="2"></Line>
<Line X1="10" Y1="20" X2="180" Y2="20" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="13">
<Line.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD8BC81" Offset="0"/>
<GradientStop Color="#FF821FE6" Offset="1"/>
<GradientStop Color="#FF3ADC93" Offset="0.55"/>
</LinearGradientBrush>
</Line.Stroke>
</Line>
</UniformGrid>
2、说明
由上面案例我们可总结以下知识点:
-
Line中X1,Y1,X2,Y2属性的设置
-
StrokeDashArray
属性可以设置线条的样式,StrokeDashArray不同的值呈现出的虚线的间隔和虚线节点长度均有不同 -
StrokeDashCap
表示虚线中每个节点起端或末尾形状(线帽),可以设置成圆形,尖角或者平头 -
StrokeStartLineCap
和StrokeEndLineCap
属性 设置Line起端或末尾形状(线帽),同样可以设置成圆形,尖角或者平头 -
对于Line而言,设置Fill无用,直接通过设置Stroke设置Line的颜色,并且可以通过Stroke设置各种Brush,包括渐变和图像
5、Polyline
Polyline 用来绘制折线,它是一系列连接的线, Polyline 元素不是封闭形状(尽管可以使用线将头尾连接,但仍旧不是封闭形状),如需创建封闭形状,推荐使用 Polygon 元素。
1、案例
<UniformGrid Height="100" Width="200" Background="White" Margin="10" Rows="4">
<Polyline Points="0,0 10,20 200,10" Stroke="Black" StrokeThickness="2" Fill="Red"/>
<Polyline Points="0,0 10,20 200,10 0,0" Stroke="Black" StrokeThickness="2" Fill="Green"/>
<Polyline Points="0,0 10,20 190,20 200,0 0,0" Stroke="Red" StrokeThickness="1" Fill="Blue"/>
<Polyline Points="10,5 10,20 190,20 190,5 10,5" StrokeDashArray="2"
StrokeDashCap="Round" Stroke="Yellow" StrokeThickness="2" Fill="Blue"/>
</UniformGrid>
2、说明
由上面案例我们可总结以下知识点:
- Polyline通过 Points 属性设置线段顶点,然后连点成多段线
- Point中的多个点的设置 ,如
Points="0,0 10,20 200,10"
表示三个坐标点(0,0),(10,20),(200,10)
依次相连 - Point 每个坐标点之间,使用空格 隔开即可
- 设置Fill 即可填充折线连接而成的形状
6、Polygon
Polygon 元素用于绘制闭合形状,同样和Polyline一样使用其 Points 属性指定形状的顶点;并且Polygon 不用指定最后一个封闭的点,该元素会自动绘制一条连接第一个点和最后一个点的线。
通过下面的对比案例了解一下:
<UniformGrid Height="100" Width="200" Background="White" Margin="10" Rows="2">
<Polyline Points="10,10 20,20 150,10" Stroke="Black" StrokeThickness="2" Fill="Red" />
<Polygon Points="10,10 20,20 150,10" Stroke="Black" StrokeThickness="2" Fill="Red" />
</UniformGrid>
7、Path
Path 类可用于绘制曲线和复杂的形状,这些曲线和形状使用 Geometry 对象进行描述。 要使用 Path,需要创建一个 Geometry 并使用它来设置 Path 对象的 Data 属性。
Path 实际上使用 Geometry 描述其内容。 通过使用 Geometry 设置 Path 的 Data 属性,并设置其 Fill 和 Stroke 属性,可以呈现 Geometry。
如:
<Path Stretch="Uniform" Fill="Black" Data="M453.44 512L161.472 220.032a41.408 41.408 0 0 1 58.56-58.56L512 453.44 803.968 161.472a41.408 41.408 0 0 1 58.56 58.56L570.56 512l291.968 291.968a41.408 41.408 0 0 1-58.56 58.56L512 570.56 220.032 862.528a41.408 41.408 0 0 1-58.56-58.56L453.44 512z" ></Path>
Path元素中的Data 属性 则是 Geometry 类型
二、Geometry(几何图形)
Geometry 是一个通用类,用于呈现 2D 图形、命中测试对象和定义剪切区域
1、Geometry和Shape的区别
Geometry 类以及从其派生的类(如 EllipseGeometry、PathGeometry 和 CombinedGeometry)可用于描述 2D 形状的几何图形;Geometry 对象可以是矩形和圆形等简单类型,也可以是由两个或更多个几何对象创建的复合类型。 可使用 PathGeometry 和 StreamGeometry 类创建更复杂的几何图形,这些类可用于描述弧线和曲线。
- Geometry 和 Shape 类的相似之处在于它们均描述 2D 形状(例如比较 EllipseGeometry 和 Ellipse),但它们之间存在一些重要区别。
- Geometry 类继承自 Freezable 类,而 Shape 类继承自 FrameworkElement。 由于它们是元素,因此 Shape 对象可以自行呈现并参与布局系统,而 Geometry 对象则不能,需要由Path来呈现。
- 尽管 Shape 对象比 Geometry 对象更易于使用,但 Geometry 对象更通用。 尽管 Shape 对象用于呈现 2D 图形,但 Geometry 对象可用于定义 2D 图形的几何区域、定义剪裁的区域或定义命中测试的区域等。
2、Geometry类型
所有几何图形的基类都是抽象类 Geometry。 派生自 Geometry 类的类可大致分为三个类别:简单几何、路径几何和复合几何。
名称 | 类型 | 作用 |
---|---|---|
LineGeometry | 简单几何 | 作用类似于Shape中的Line |
RectangleGeometry | 简单几何 | 作用类似于Shape中的Rectangle |
EllipseGeometry | 简单几何 | 作用类似于Shape中的Ellipse |
GeometryGroup | 用于创建复合几何 | 为单个路径添加任意多个Geometry对象,使用EvenOdd或NonZero填充规则来确定要填充的区域。 |
CombinedGeometry | 用于创建复合几何 | 将两个几何图形合并为一个形状。可使用CombineMode属性选择如何组合两个几何图形。 |
PathGeometry | 路径几何 | 代表更复杂的弧线、曲线以及直线构成的图形,并且既可以是闭合的,也可以是不闭合的。 |
StreamGeometry | 路径几何 | 相当于PathGeometry的只读轻量级。StreamGeometry图形可节省内存,因为它不在内存中同时保存路径的所有分段。并且这类图形一旦被创建就不能再修改。 |
3、简单几何 LineGeometry、RectangleGeometry 和 EllipseGeometry
首先这里面的坐标体系,同Shape中的坐标体系是一样的,设置水平X和竖直Y轴,都类似于设置Margin的左间隔和上间隔的值
- LineGeometry 通过指定直线的起点StartPoint和终点EndPoint来定义。
- EllipseGeometry 由中心点Center、X半径和 Y 半径定义。
- RectangleGeometry 使用 Rect 结构来定义,该结构指定其相对位置以及高度和宽度。 可以通过设置 RadiusX 和 RadiusY 属性来创建圆角矩形。
下面分别查看案例:
<StackPanel Height="100" Width="200" Background="White" Margin="10" Orientation="Horizontal">
<Line X1="10" Y1="10" X2="20" Y2="50" Stroke="Red" StrokeThickness="4" StrokeEndLineCap="Round"></Line>
<Path Stroke="Green" StrokeThickness="4" StrokeEndLineCap="Round">
<Path.Data>
<LineGeometry StartPoint="10,10" EndPoint="20,50"></LineGeometry>
</Path.Data>
</Path>
</StackPanel>
<StackPanel Height="100" Width="200" Background="White" Margin="10" Orientation="Horizontal">
<Ellipse Height="40" Width="40" Stroke="Red" StrokeThickness="4" Fill="Green"></Ellipse>
<Path Stroke="Green" StrokeThickness="4" Fill="Red">
<Path.Data>
<EllipseGeometry Center="40,50" RadiusX="20" RadiusY="20"></EllipseGeometry>
</Path.Data>
</Path>
</StackPanel>
//使用代码创建矩形 Path中的实例代码:
//其余类型的Path想使用代码创建,同理
RectangleGeometry myRectangleGeometry = new RectangleGeometry();
myRectangleGeometry.Rect = new Rect(50,50,25,25);
Path myPath = new Path();
myPath.Fill = Brushes.LemonChiffon;
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1;
myPath.Data = myRectangleGeometry;
补充:可以通过设置 RadiusX 和 RadiusY 属性来调整EllipseGeometry 矩形的圆角大小,设置为大于零的值。 值越大,EllipseGeometry 矩形的角越圆。
4、PathGeometry路径几何
PathGeometry 类及其轻型等效项(StreamGeometry 类)提供了描述由弧线、曲线和直线组成的多个复杂图形的方法。
1. PathGeometry中的层级关系
PathGeometry 的核心是 PathFigure 对象的集合,之所以如此命名,是因为每个图形都描述 PathGeometry 中的一个离散形状。 每个 PathFigure 本身都由一个或多个 PathSegment 对象组成,其中每一个都描述了图形的一个线段。
<Path Stroke="Green" StrokeThickness="20" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="20,20">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="20,130"/>
<LineSegment Point="200,130"/>
<LineSegment Point="200,260"/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
- PathGeometry 对象由一个或多个 PathFigure 对象组成;
- 每个 PathFigure 本身由一个或多个 PathSegment 对象组成
<PathGeometry.Figures>
内的PathFigureCollection 和<PathFigure.Segments>
内的PathSegmentCollection 两个标签是可以省略的
2. PathFigure 和 PathSegment
- PathFigure 代表不同的“图形”或形状,PathSegment 代表图形或形状中的组成部件线段。
- PathFigure 内的多个线段组合成单个几何形状,每个线段的终点是下一个线段的起点。
- PathFigure 的 StartPoint 属性指定绘制第一个线段的起点。 每个后续段都从上一段的终点开始。
PathFigure 中属性 | 说明 |
---|---|
StartPoint | 指示从何处开始绘制图形的Point对象。 |
Segments | 用于绘制图形的PathSegment对象的集合。 |
IsClosed | 指定是否连接PathFigure 的起点和终点,如果为True,不连接,反之,则连接起点和终点。默认False |
IsFilled | 是否该PathFigure可用于进行命中测试,呈现和剪辑。 如果为True,就使用Path.Fill画刷填充图形内部的区域。 |
PathSegment 线段类型 | 说明 |
---|---|
LineSegment | 创建两个点之间的直线。 |
ArcSegment | 在两点之间创建一条椭圆弧。 |
QuadraticBezierSegment | 创建二次贝塞尔曲线。 |
BezierSegment | 在两点之间创建一个三次方贝塞尔曲线。 |
PolyLineSegment | 创建一系列直线。 |
PolyQuadraticBezierSegment | 创建一系列二次贝塞尔曲线。 |
PolyBezierSegment | 创建一系列三次方贝塞尔曲线。 |
LineSegment 和PolyLineSegment的使用
-
LineSegment 创建两个点之间的直线.
PathFigure 的 StartPoint 属性指定绘制第一个线段的起点,LineSegment 中的Point属性,就是设置线段的终点坐标;第一个LineSegment 的终点,将作为下一个LineSegment 的起点,依次类推。 -
PolyLineSegment创建一系列直线。
PathFigure 的 StartPoint 属性指定绘制第一个线段的起点,PolyLineSegment中的Points属性是一个Point的集合,如上案例中Points="100,100 250,50 50,50"
则表示 三个坐标点(100,100)、 (250,50)、 (50,50) ,坐标内用逗号分开,每一对坐标之间用空格分开。
ArcSegment 的使用
ArcSegment在两点之间创建一条椭圆弧。
- Size 获取或设置椭圆弧的 X轴半径和Y轴半径
- RotationAngle 获取或设置椭圆围绕x轴旋转的角度,默认值为0
- IsLargeArc 获取或设置一个值,该值指示椭圆弧是否应大于180度;当设置为true的时候,绘制的椭圆弧大于180,反之,小于180度
- SweepDirection 获取或设置一个值,制定该值是以Clockwise顺时针方向绘制椭圆弧,还是以Counterclockwise 逆时针方向绘制椭圆弧
- Point 获取或设置椭圆弧的终点
使用ArcSegment绘制一个椭圆
<Path Stroke="LightGreen" StrokeThickness="5">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="100,200">
<PathFigure.Segments>
<ArcSegment Size="80,50" IsLargeArc="True" RotationAngle="0" SweepDirection="Clockwise" Point="200,200" />
<ArcSegment Size="80,50" IsLargeArc="False" RotationAngle="0" SweepDirection="Clockwise" Point="100,200" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
QuadraticBezierSegment 和 PolyQuadraticBezierSegment 的使用
关于贝塞尔曲线的数学原理可查看贝塞尔曲线原理,本文将从该文截取部分内容,辅助介绍该知识点。
二次贝塞尔曲线的原理图如下所示:
上图中P0为起点,P1为控制点,P2为终点,三点绘制一个二次贝塞尔曲线。
PathFigure的StartPoint属性确定了曲线的起点,QuadraticBezierSegment 的Point1属性则是确定了贝塞尔曲线的控制点坐标,Point2属性确定了贝塞尔曲线的终点坐标,由此便可以绘制一条贝塞尔曲线。
<Path Stroke="LightGreen" StrokeThickness="5">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="50,50">
<PathFigure.Segments>
<PolyQuadraticBezierSegment Points="200,200 300,100 400,200 600,50" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
PolyQuadraticBezierSegment 就是创建一系列二次贝塞尔曲线,可以通过Points属性设置一系列的Point来完成。如上案例中:<PolyQuadraticBezierSegment Points="200,200 300,100 400,200 600,50" />
则表示有两个二次贝塞尔曲线,第一个曲线的Point1为(200,200),Point2为(300,100) ;第二个曲线的Point1为(400,200),Point2为(600,50) ;
BezierSegment 和PolyBezierSegment 的使用
BezierSegment用于在两点之间创建一个三次方贝塞尔曲线。首先我们看下三次放贝塞尔曲线的原理图:
上图中P0为起点,P1,P2为控制点,P3为终点,三点绘制一个三次贝塞尔曲线。
PathFigure的StartPoint属性确定了曲线的起点,BezierSegment的Point1,Point2属性则是确定了三次贝塞尔曲线的两个控制点坐标,Point3属性确定了三次贝塞尔曲线的终点坐标,由此便可以绘制一条三次贝塞尔曲线。
PolyBezierSegment用于创建一系列三次方贝塞尔曲线。具体使用如下图所示:
<Path Stroke="LightGreen" StrokeThickness="5">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="50,50">
<PathFigure.Segments>
<PolyBezierSegment Points="0,0 200,0 300,100 300,0 400,0 600,100" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
5、StreamGeometry
在创建几何形状时,StreamGeometry 是对 PathGeometry 的轻量替代。 当需要描述复杂几何形状,但又不希望产生支持数据绑定、动画或修改的开销时,请使用 StreamGeometry。 由于 StreamGeometry 类的高效性,该类是描述装饰器的不错选择
使用StreamGeometry有两种方式,一种是使用路径标记语法中的微语言(下文会做详解),另一种就是使用代码的形式创建
- StreamGeometry微语言的语法如下:
<!--绘制一个三角形-->
<Path Data="F0 M10,100 L100,100 100,50Z" StrokeThickness="1" Stroke="Black"/>
- 使用代码的形式 使用
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace SDKSample
{
// 使用StreamGeometry和StreamGeometryContext来定义一个三角形。
public partial class StreamGeometryTriangleExample : Page
{
public StreamGeometryTriangleExample()
{
// 建立路径以绘制几何图形。
Path myPath = new Path();
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1;
// 创建用于指定myPath的StreamGeometry。
StreamGeometry geometry = new StreamGeometry();
geometry.FillRule = FillRule.EvenOdd;
//打开可用于描述此StreamGeometry对象内容的StreamGeometry Context。
using (StreamGeometryContext ctx = geometry.Open())
{
//从指定的点开始三角形。请注意,该形状被设置为关闭所以只需要在下面指定两条线就可以构成三角形。
ctx.BeginFigure(new Point(10, 100), true /* is filled */, true /* is closed */);
//画一条线到下一个指定的点。
ctx.LineTo(new Point(100, 100), true /* is stroked */, false /* is smooth join */);
//画另一条线到下一个指定的点。
ctx.LineTo(new Point(100, 50), true /* is stroked */, false /* is smooth join */);
}
//冻结几何图形(使其不可修改),以获得额外的性能优势。
geometry.Freeze();
//使用StreamGeometry指定路径的形状(三角形)。
myPath.Data = geometry;
//将路径形状添加到UI。
StackPanel mainPanel = new StackPanel();
mainPanel.Children.Add(myPath);
this.Content = mainPanel;
}
}
}
6、路径标记语法- 微型语言
1. StreamGeometry和 PathFigureCollection 微型语言
WPF 提供了两个类,它们提供了用于描述几何路径的微型语言:StreamGeometry 和 PathFigureCollection。
- 设置 Geometry 类型的属性(例如 UIElement 元素的 Clip 属性或 Path 元素的 Data 属性)时,可以使用 StreamGeometry 微型语言。 以下示例使用属性语法创建 StreamGeometry。
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<StreamGeometry x:Key="sg">F0 M10,100 L100,100 100,50Z</StreamGeometry>
</StackPanel.Resources>
<!--形式1:直接使用Data-->
<Path Data="F0 M10,100 L100,100 100,50Z" StrokeThickness="1" Stroke="Black" Fill="Red"/>
<!--形式2:使用StreamGeometry-->
<Path Stroke="Black" Fill="Green">
<Path.Data>
<StreamGeometry>F0 M10,100 L100,100 100,50Z</StreamGeometry>
</Path.Data>
</Path>
<!--形式3:将StreamGeometry 作为资源引用-->
<Path Data="{StaticResource sg}" StrokeThickness="1" Stroke="Black" Fill="Pink"/>
</StackPanel>
- 在设置 PathGeometry 的 Figures 属性时,可以使用 PathFigureCollection 微型语言。 以下示例使用属性语法为 PathGeometry 创建 PathFigureCollection。
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<PathGeometry x:Key="sg">M 10,100 C 10,300 300,-200 300,100</PathGeometry>
</StackPanel.Resources>
<!--形式1-->
<Path Stroke="Black" Fill="Green">
<Path.Data>
<PathGeometry Figures="M 10,100 C 10,300 300,-200 300,100" />
</Path.Data>
</Path>
<!--形式2-->
<Path Stroke="Black" Fill="Green">
<Path.Data>
<PathGeometry>M 10,100 C 10,300 300,-200 300,100</PathGeometry>
</Path.Data>
</Path>
<!--形式3-->
<Path Data="{StaticResource sg}" Stroke="Black" Fill="LightGreen"/>
</StackPanel>
由上我们发现StreamGeometry 和PathGeometry几乎是等效的,那么的使用场景有什么不同呢?
在创建路径后无需修改路径时,请使用 StreamGeometry;如果需要修改路径,请使用 PathGeometry。
2. 微型语言中的空格和逗号,特殊值
- 微型语言中空格的使用,为简洁起见,微型语言语法部分中使用一个空格,作为Point 或其他功能的分隔作用,但在显示一个空格的地方,多个空格也可以接受。
- 微型语言中的Point的X坐标和Y坐标使用逗号
(,)
表示,语法格式为x,y
- 除了标准数值外,还可使用以下特殊值。 这些值区分大小写。
-
- 无穷大 表示 Double.PositiveInfinity。
-
- Infinity 表示 Double.NegativeInfinity。
-
- NaN 表示 Double.NaN。
3. 微型语言的语法
StreamGeometry 的XAML微型语言 由可选的 FillRule 值和一个或多个图形描述组成。
<!--语法格式-->
<objectproperty="[ fillRule] figureDescription[ figureDescription]* " ... />
PathFigureCollection 的 XAML微型语言 由一个或多个图形描述组成。
<!--语法格式-->
<objectproperty="figureDescription[ figureDescription]* " ... />
StreamGeometry 微型语言 和PathFigureCollection 的 微型语言 语法是一样的,只不过在描述格式上:StreamGeometry 微型语言比PathFigureCollection 微型语言多了一个可选填充规则的描述命令。
术语 | 描述 |
---|---|
fillRule | 指定 StreamGeometry 是使用 EvenOdd 还是 NonzeroFillRule。 - F0 指定 EvenOdd 填充规则。- F1 指定 Nonzero 填充规则。 如果省略该命令,子路径将使用默认行为,即 EvenOdd。 |
figureDescription | 图形由一个移动命令,绘制命令和一个可选的关闭命令组成。格式如:moveCommand drawCommands [ closeCommand ] |
moveCommand | 用于指定图形起点的移动命令。 |
drawCommands | 用于描述图形内容的一个或多个绘图命令。 |
closeCommand | 用于关闭图形的可选关闭命令。 |
- 移动命令
命令类型 | 命令的表示字母 | 描述 |
---|---|---|
移动命令 | M/m | 指定新图形的起点。 指定的就是<PathFigure StartPoint="50,50"> 中的StartPoint 使用语法: M startPoint 或 m startPoint, 示例:M20,20 或m20,20 M表示startPoint 是个绝对值,m表示startPoint 是一个相对值,是对前一个点的偏移,如果都不存在的话,则为(0,0) |
- 绘制命令
绘制命令可以由几个形状命令组成。 以下形状命令可用:直线、水平线、竖线、三次贝塞尔曲线、二次贝塞尔曲线、平滑三次贝塞尔曲线、平滑二次贝塞尔曲线和椭圆弧。
可以使用大写或小写字母输入每个命令:大写字母表示绝对值,小写字母表示相对值:该线段的控制点相对于前面示例的终点。 当按顺序输入多个相同类型的命令时,可以省略重复的命令输入;例如,L 100,200 300,400 相当于 L 100,200 L 300,400。 下表描述了“移动”和“绘制”命令。
命令类型 | 命令的表示字母 | 描述 |
---|---|---|
直线命令 | L/l | - 在当前点和指定的终点之间创建一条直线。 指定的就是LineSegment 中的Point 线条 的终点, - 使用语法: L endPoint或 l endPoint, 示例:L20,20 或l20,20 - L表示endPoint 是个绝对值,l表示endPoint 是一个相对值,是对前一个点的偏移,如果都不存在的话,则为(0,0) |
水平线命令 | H/h | - 在当前点和指定的 x 坐标之间创建一条水平线。 指定的就是线条终点的 x 坐标, - 相当于是直线命令中对水平线的一种快捷命令方式 - 使用语法: H x或 h x, 示例:H90 或h90 - H 表明 x 是一个绝对值; h 表明 x 是对前一点的偏移,如果都不存在的话,则为 (0,0)。 |
竖线命令 | V/v | - 在当前点和指定的 y 坐标之间创建一条竖线。 指定的就是线条终点的 y 坐标, - 相当于是直线命令中对竖线的一种快捷命令方式 - 使用语法: V y或 v y, 示例:V20 或v20 - V 表明 y 是一个绝对值; v 表明 y 是对前一点的偏移,如果都不存在的话,则为 (0,0)。 |
二次贝塞尔曲线命令 | Q/q | - 使用指定的控制点 (controlPoint),在当前点和指定的终点之间创建二次贝塞尔曲线 - 使用语法: Q controlPoint endPoint 或 q controlPoint endPoint, 示例:q 100,200 300,200 |
三次贝塞尔曲线命令 | C/c | - 通过使用两个指定的控制点(controlPoint1 和 controlPoint2),在当前点和指定的终点之间创建三次贝塞尔曲线。 - 使用语法: C controlPoint1 controlPoint2 endPoint或c controlPoint1 controlPoint2 endPoint, 示例:C 100,200 200,400 300,200 |
平滑二次贝塞尔曲线命令 | T/t | - 在当前点和指定的终点之间创建二次贝塞尔曲线。 假设控制点为相对于当前点前一命令的控制点的反射。 如果没有前一命令或如果前一命令不是二次贝塞尔曲线命令或平滑二次贝塞尔曲线命令,则控制点与当前点重合。 - 使用语法: T endPoint或 t endPoint, 示例:T20,20 |
平滑三次贝塞尔曲线命令 | S/s | - 在当前点和指定的终点之间创建三次贝塞尔曲线。 假设第一控制点为相对当前点前一命令的第二控制点的反射。 如果没有前一命令或如果前一命令不是三次贝塞尔曲线命令或平滑三次贝塞尔曲线命令,则假设第一个控制点与当前点重合。 第二个控制点(曲线末尾的控制点)由 controlPoint2 指定。 - 使用语法: S controlPoint2 endPoint或 s controlPoint2 endPoint, 示例:S 100,200 200,300 |
椭圆弧命令 | A/a | - 在当前点和指定的终点之间创建一个椭圆弧。 - 使用语法: A size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint 或 a size rotationAngle isLargeArcFlag sweepDirectionFlag endPointcontrolPoint endPoint, 示例:A 100,50 45 1 0 200,100 - size 表示圆弧的x轴和y轴半径 - rotationAngle 表示椭圆旋转的角度 - isLargeArcFlag 如果圆弧角度应为 180 度或更大,请设置为 1,否则设置为 0。 - sweepDirectionFlag 如果以顺时针方向绘制圆弧,请设置为 1;否则设置为 0。 - endPoint 表示椭圆弧终点 |
- 关闭命令
命令类型 | 命令的表示字母 | 描述 |
---|---|---|
关闭命令 | Z/z | 结束当前图形,并创建一条将当前点连接到图形起点的直线。 此命令可以在图形最后一段与第一段之间创建一条连接线(角)。 使用语法: Z 或 z |
4. 微型语言案例理解
理解移动命令和直线命令以及绝对坐标和相对坐标
- 每一个M代表的就是一个图形PathFigure的StartPoint,当Data中有多个M则表示该复合图形中有多个PathFigure,同一个PathFigure内的线段,后一个线段起点会接着上一个线段的终点,但是每个PathFigure是独立图形 不会接着上一个PathFigure的终点进行绘制。
- 当我们需要在复合几何图形中再画一个图形的时候,都需要使用M命名
- 绝对坐标:就是图形中所有的点,都使用控件的坐标原点和坐标体系
- 相对坐标:就是相对于上一个点的偏移坐标,坐标原点一直在变,如分别连接A,B,C三个点,如果是相对坐标,那么B将以A的坐标作为坐标原点,C将以B的坐标作为坐标原点
各微语言命令的使用
<StackPanel Orientation="Vertical">
<!--移动命令M和直线命令L的使用-->
<Path Stroke="Black" StrokeThickness="3" Data="M 10,30 L 200,10" />
<!--水平线命令H和竖线命令V的使用-->
<WrapPanel>
<Path Stroke="Red" StrokeThickness="3" Data="M 10,20 H200 V80" />
<Path Stroke="Red" StrokeThickness="3" Data="M 10,20 h200 v80" />
</WrapPanel>
<!--关闭命令Z的使用-->
<WrapPanel>
<Path Stroke="Pink" StrokeThickness="3" Data="M 10,50 H200 V100Z" Fill="DeepPink"/>
<Path Stroke="Pink" StrokeThickness="3" Data="M 10,50 H200 V100Z M 200,50 h100 V100Z" Fill="DeepPink"/>
</WrapPanel>
<!--填充规则命令F0和F1的使用-->
<WrapPanel>
<Path Data="F1 M10,10 h150 v100 M70,25 h70 v50 Z" StrokeThickness="1" Fill="Green" Stroke="Black"/>
<Path Data="F0 M10,10 h150 v100 M70,25 h70 v50 Z" StrokeThickness="1" Fill="Green" Stroke="Black"/>
</WrapPanel>
<!--椭圆弧绘制命令A的使用-->
<WrapPanel>
<Path Stroke="Blue" StrokeThickness="5" Data="M 10,10 A 50,30 0 1 0 200,20" />
<Path Stroke="Blue" StrokeThickness="5" Data="M 10,10 A 30,30 0 1 0 200,20Z" Fill="LightBlue"/>
</WrapPanel>
<!--二次贝塞尔曲线命令Q 和平滑二次贝塞尔曲线命令T的使用-->
<WrapPanel>
<Path Stroke="Orange" StrokeThickness="5" Data="M 10,10 Q 20,130 200 50" />
<Path Stroke="Orange" StrokeThickness="5" Data="M 10,10 T 20,130" />
</WrapPanel>
<!--三次贝塞尔命令C 和平滑三次贝塞尔命令S的使用-->
<WrapPanel>
<Path Stroke="Brown" StrokeThickness="5" Data="M 20,120 C 100,0 200,200 300,100" />
<Path Stroke="Brown" StrokeThickness="5" Data="M 20,120 S 200,200 300,100" />
</WrapPanel>
</StackPanel>
5. SVG在线编辑工具推荐
通过以上的介绍,我们基本可以绘制一些自己想要的图形了,但是每个图形都要自行绘制,确实是太麻烦了,因此大多时候,我们都会从网上(如iconfont网站)下载一些图片的svg代码,然后使用svg代码作为Path的Data数据。svg代码对应的就是WPF中微型语言。下面推荐一个绘制SVG图片的在线网站:SVG在线编辑工具
7、复合几何
使用 GeometryGroup
、CombinedGeometry
或通过调用静态 Geometry 方法 Combine,可以创建复合几何对象。
对象 | GeometryGroup 和CombinedGeometry 异同点描述 |
---|---|
CombinedGeometry | CombinedGeometry 对象和 Combine 方法执行布尔运算,以合并由两个几何图形定义的面积。 没有面积的 Geometry 对象将被放弃。 只能合并两个Geometry 对象(尽管这两个几何图形也可能是复合几何)。 |
GeometryGroup | GeometryGroup类创建其包含的 Geometry 对象的合并,而不合并其面积。 可以将任意数量的 Geometry 对象添加到 GeometryGroup。 |
GeometryGroup | 由于GeometryGroup不执行合并操作,因此使用 GeometryGroup 对象的性能比使用 CombinedGeometry 对象或 Combine 方法的性能高。 |
1. 使用GeometryGroup创建复合形状
由于GeometryGroup
也是派生自Geometry,需要通过Path来呈现,而Path 的Data属性就是Geometry类型,因此我们将需要的呈现的复合对象放置在Data中即可。
- GeometryGroup 的基本使用,简单几何图形的复合
<Grid>
<Path Stroke="Green" Fill="LightGreen" StrokeThickness="20" Margin="10">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<LineGeometry StartPoint="100,0" EndPoint="100,200"></LineGeometry>
<LineGeometry StartPoint="0,100" EndPoint="200,100"></LineGeometry>
<RectangleGeometry Rect="50,50 100,100"></RectangleGeometry>
<EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"></EllipseGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</Grid>
- GeometryGroup 的FillRule属性的简单使用
上图结论仅是两个图形的时候的简单总结,便于日常的使用理解,实际上官方的解释是:
- EvenOdd:此规则通过从一点向任意方向绘制一条射向无穷远的射线,然后计算给定形状中与该射线相交的路径段的数量,从而确定该点是否位于填充区域中。 如果此数目为奇数,那么该点则在内部;如果为偶数,则该点在外部。
- NonZero:此规则通过从一点向任意方向绘制一条射向无穷远的射线,并检查一段形状与射线相交的位置,从而确定该点是否位于路径的填充区域。 从零计数开始,从左到右每次添加与射线相交的一个段,然后从右到左每次减去与射线相交的一个路径段。 在对交叉点进行计数后,如果结果为零,那么该点则位于路径外。 否则,该点则在路径内。
- GeometryGroup 对于复杂几何图形的复合
由于我们可以将任意数量的 Geometry 对象添加到 GeometryGroup,而Geometry的派生类而非仅仅有LineGeometry、RectangleGeometry 和 EllipseGeometry等简单几何的,还有PathGeometry 和GeometryGroup 以及StreamGeometry。因此我们可以使用GeometryGroup 进行很多复杂几何的组合。
- GeometryGroup 常用的常用场景:使用svg图片
- 使用代码创建复合几何
// Create a Path to be drawn to the screen.
Path myPath = new Path();
myPath.Stroke = Brushes.Black;
myPath.StrokeThickness = 1;
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(255, 204, 204, 255);
myPath.Fill = mySolidColorBrush;
// Create the line geometry to add to the Path
LineGeometry myLineGeometry = new LineGeometry();
myLineGeometry.StartPoint = new Point(10, 10);
myLineGeometry.EndPoint = new Point(50, 30);
// Create the ellipse geometry to add to the Path
EllipseGeometry myEllipseGeometry = new EllipseGeometry();
myEllipseGeometry.Center = new Point(40, 70);
myEllipseGeometry.RadiusX = 30;
myEllipseGeometry.RadiusY = 30;
// Create a rectangle geometry to add to the Path
RectangleGeometry myRectGeometry = new RectangleGeometry();
myRectGeometry.Rect = new Rect(30, 55, 100, 30);
// Add all the geometries to a GeometryGroup.
GeometryGroup myGeometryGroup = new GeometryGroup();
myGeometryGroup.Children.Add(myLineGeometry);
myGeometryGroup.Children.Add(myEllipseGeometry);
myGeometryGroup.Children.Add(myRectGeometry);
myPath.Data = myGeometryGroup;
// Add path shape to the UI.
StackPanel mainPanel = new StackPanel();
mainPanel.Children.Add(myPath);
this.Content = mainPanel;
2. 使用CombinedGeometry 合并几何
CombinedGeometry 不可直接放置几何图形,必须且只能通过Geometry1和Geometry2来承接
由上可知:设置GeometryCombineMode 属性的时候就可以改变内部几何图形的组合规则;
- 当设置为Xor 时,创建包含两个几何图形非共有区域的形状。
- 当设置为Union时,创建包含两个几何图形所有区域的形状
- 当设置为Exclude时,创建的形状包含第一个几何图形的所有区域,但不包含第二个几何图形的区域。
- 当设置为Intersect时,创建包含两个几何图形共有区域的形状。
6、使用Geometry作为属性的对象
将 Geometry 对象与其他对象结合可用于各种目的,如绘制形状、动画处理和剪裁。 下表列出了多个类,这些类具有采用 Geometry 对象的属性。
类型 | 属性 |
---|---|
DoubleAnimationUsingPath | PathGeometry |
DrawingGroup | ClipGeometry |
GeometryDrawing | Geometry |
Path | Data |
UIElement | Clip |
1.UIElement的Clip属性案例
<StackPanel Height="100" Width="200" Background="White" Margin="10" Orientation="Horizontal">
<Image Width="50" Height="50" HorizontalAlignment="Left" Source="/MvvmDemo;component/Res/Images/lg.png" />
<Image Width="50" Height="50" HorizontalAlignment="Left" Source="/MvvmDemo;component/Res/Images/lg.png" >
<Image.Clip>
<EllipseGeometry RadiusX="25" RadiusY="25" Center="25,25"/>
</Image.Clip>
</Image>
</StackPanel>
由于Clip的属性是Geometry类型,因此裁剪形状不仅仅局限于某一种,而是根据需要你可以裁剪出任意形状
结语
以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。
参考资料
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)