Line:直线段,可以设置其笔触(Stroke)。
Rectangle:矩形,既有笔触,又有填充(Fill)。
Ellipse:椭圆,长、宽相等的椭圆即为正圆,既有笔触又有填充。
Polygon:多边形,由多条直线段围城的闭合区域,既有笔触又有填充。
Polyline:折线(不闭合),由多条首尾相接的直线段组成。
Path:路径(闭合区域),基本图形中功能最强大的一个,可由若干直线、圆弧、贝塞尔曲线组成。
日常工作中,常用的绘图容器是Canvas和Grid。
一、矩形
矩形由笔触(Stroke,即边线)和填充(Fill)构成。Stroke属性的设置与Line一样,Fill属性的数据类型是Brush。Brush是个抽象类,所以我们不可能拿一个Brush类的实例为Fill属性赋值而只能用Brush派生类的实例进行赋值。WPF的绘图系统包含非常丰富的Brush类型,常用的有:
SolidColorBrush:实心画刷。在XAML中可以使用颜色名称字符串(如Red、Blue)直接赋值。
LinearGradientBrush:线性渐变画刷。色彩沿设定的直线方向、按设定的变化点进行渐变。
RadialGrandientBrush:径向渐变画刷。色彩沿半径的方向、按设定的变化点进行渐变,形成圆形填充。
ImageBrush:使用图片(Image)作为填充内容。
DrawingBrush:使用矢量图(Vector)和位图(Bitmap)作为填充内容。
VisualBrush:WPF中的每个控件都是由FrameWorkElement类派生来的,而FrameworkElement又是由Visual类派生来的的。Visual意为“可视”之意,每个控件的可视化形象就可以通过Visual类的方法获得。获得这个可视化的形象后,我们可以用这个形象进行填充,这就是VisualBrush。比如当我想把窗体上的某个控件拖拽到另一个位置,当鼠标松开之前需要在鼠标指针下显现一个控件的“幻影”,这个“幻影”就是使用VisualBrush填充出来的一个矩形,并让矩形捕捉鼠标的位置、随鼠标移动。
二、椭圆
椭圆也是一种常用的几何图形,它的使用方法与矩形没有什么区别。正圆(Circle),Width与Height相等的椭圆既是正圆。
三、路径
路径(Path)可以说是WPF绘图中最强大的工具,一来是因为它完全可以替代其他几种几何图形,二来它可以将直线、圆弧、贝塞尔曲线等基本元素结合进来,形成更复杂的图形。路径最重要的一个属性是Data,Data的数据类型是Geometry(几何图形),我们正式使用这个属性将一些基本的线段拼接起来、形成复杂的图形。
为Data属性赋值的语法有两种:一种是标签式的标准语法,另一种是专门用于绘制几何图形的“路径标记语法”。
Geometry的子类包括:
LineGeometry:直线几何图形。
RectangleGeometry:矩形几何图形。
EllipseGeometry:椭圆几何图形。
PathGeometry:路径几何图形。
StreamGeometry:PathGeometry的轻量级替代品,不支持Binding、动画等功能。
CombinedGeometry:由多个基本几何图形联合在一起,形成的单一几何图形。
GeometryGroup:由多个基本几何图形组合在一起,形成的几何图形组。
<Window x:Class="WPFLearn.DrawAndAnimation.PathGeometry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PathGeometry" Height="350" Width="340">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"/>
<ColumnDefinition Width="160"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="160"/>
<RowDefinition Height="160"/>
</Grid.RowDefinitions>
<!--直线-->
<Path Stroke="Blue" StrokeThickness="2" Grid.Column="0" Grid.Row="0">
<Path.Data>
<LineGeometry StartPoint="20,20" EndPoint="140,140"/>
</Path.Data>
</Path>
<!--矩形路径-->
<Path Stroke="Orange" Fill="Yellow" Grid.Column="1" Grid.Row="0">
<Path.Data>
<RectangleGeometry Rect="20,20,120,120" RadiusX="10" RadiusY="10"/>
</Path.Data>
</Path>
<!--椭圆路径-->
<Path Stroke="Green" Fill="LawnGreen" Grid.Row="1" Grid.Column="0">
<Path.Data>
<EllipseGeometry Center="80,80" RadiusX="60" RadiusY="40"/>
</Path.Data>
</Path>
<!--自定义路径(最为重要)-->
<Path Stroke="Yellow" Fill="Orange" Grid.Column="1" Grid.Row="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="25,140" IsClosed="True">
<PathFigure.Segments>
<LineSegment Point="20,40"/>
<LineSegment Point="40,110"/>
<LineSegment Point="50,20"/>
<LineSegment Point="80,110"/>
<LineSegment Point="110,20"/>
<LineSegment Point="120,110"/>
<LineSegment Point="140,40"/>
<LineSegment Point="135,140"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Window>
Figures是PathGeometry的默认内容属性、Segments是PathFigure的默认内容属性,所以常简化为这样:
<Path>
<Path.Data>
<PathGeometry>
<PathFigure>
<!--各种线段-->
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
LineSegment:直线段。
ArcSegment:圆弧线段。
BezierSegment:三次方贝塞尔曲线段(默认贝塞尔曲线就是指三次曲线,所以Cubic一词被省略)。
QuadraticBezierSegment:二次方贝塞尔曲线段。
PolyLineSegment:多直线段。
PolyBezierSegment:多三次方贝塞尔曲线段。
PolyQuadraticBezierSegment:多二次方贝塞尔曲线。
在绘制这些线段的时候需要注意,所以这些线段都是没有起点(StartPoint)的,因为起点就是前一个线段的终点,而第一个线段的起点这是PathFigure的StartPoint。
<Window x:Class="WPFLearn.DrawAndAnimation.LineSegment"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LineSegment" Height="300" Width="300">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Path Stroke="Green" Fill="LawnGreen" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="0,0">
<LineSegment Point="150,0"/>
<LineSegment Point="150,30"/>
<LineSegment Point="90,30"/>
<LineSegment Point="90,150"/>
<LineSegment Point="60,150"/>
<LineSegment Point="60,30"/>
<LineSegment Point="0,30"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Window>
ArcSegment用来绘制圆弧。
Point属性用来指定圆弧连接的终点;
圆弧截取自椭圆,Size属性即是完整椭圆的横轴半径和纵轴半径;
SweepDirection 属性指明圆弧是顺时针方向还是逆时针方向;
如果椭圆上的两点位置不对称,那么这两点的椭圆就会分为大弧和小弧,
IsLargeArc属性用于指明是否使用大弧去连接;
RotationAngle属性用来指明圆弧母椭圆的旋转角度。
BezierSegment(三次方贝塞尔曲线)由4个点决定:
⑴ 起点:即前一个线段的终点或PathFigure的StartPoint。
⑵ 终点:Point3属性,即曲线的终点位置。
⑶ 两个控制点:Point1和Point2属性。
<Window x:Class="WPFLearn.DrawAndAnimation.BezierSegment"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BezierSegment" Height="300" Width="300">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="250,0" Point2="50,200" Point3="300,200"></BezierSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Window>
QuadraticBezierSegment(二次方贝塞尔曲线)与BezierSegment类似,只是控制点由两个减少为一个。也就是说,QuadraticBezierSegment由3个点决定:
⑴ 起点:即前一个线段的终点或PathFigure的StartPoint。
⑵ 终点:Point3属性,即曲线的终点位置。
⑶ 一个控制点:Point1。
<Window x:Class="WPFLearn.DrawAndAnimation.QuadraticBezierSegment"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="QuadraticBezierSegment" Height="300" Width="300">
<Grid>
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,200">
<QuadraticBezierSegment Point1="150,-100" Point2="300,200"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Window>
GeometryGroup也是Geometry的一个派生类,它最大的特点是可以将一组PathGeometry组合在一起、
<Window x:Class="WPFLearn.DrawAndAnimation.GeometryGroup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GeometryGroup" Height="300" Width="300">
<Grid>
<Path Stroke="Black" Fill="LightBlue" StrokeThickness="1">
<Path.Data>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="250,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="210,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="190,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="170,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="150,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment Point1="130,0" Point2="50,200" Point3="300,200"/>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
</Grid>
</Window>
路径标记语法
Path是如此之强大,可以让我们随心所欲地绘制图形,然而它的一大缺点也是不容忽视的,那就是其标签式语法的反锁。
路径标记语法实际上就是各种线段的简记法,比如<LineSegment Point=“150,5”>可以简写为“L 150,5”,这个L就是路径标记语法的一个“绘图命令”。
命令 | 用途 | 语法 | 示例 | 对应标签式语法 | 分类 |
M | 移动到起始点 | M 起始点 | M 10,10 | <PathFigure StartPoint="0,0"/> | 移动命令 |
L | 绘制直线 | L 终点 | L 150,30 | <LineSegment Point="150,30"/> | 绘图命令 |
H | 绘制水平直线 | H 终点横坐标 | H 180 | 绘图命令 | |
V | 绘制竖直直线 | V终点纵坐标 | V 180 | 绘图命令 | |
A | 绘制圆弧 | A 母椭圆尺寸 旋转角度 是否大弧 顺/逆时针 终点 | A 180,80 45 1 1 150,150 | <ArcSegment Size="180,180" RotationAngle="45" IsLargeArc="True" SweepDirection="Clockwise" Point="150,150"/> | 绘图命令 |
C | 三次方贝塞尔曲线 | C 控制点1 控制点2 终点 | C 250,0 50,200 300,200 | <BezierSegment Point1="250,0" Point2="50,200" Point3="300,200"/> | 绘图命令 |
Q | 二次方贝塞尔曲线 | Q 控制点1 终点 | Q 150,-100 300,200 | <QuadraticBezierSegment Point1="150,-100" Point2="300,200"/> | 绘图命令 |
S | 平滑三次贝塞尔曲线 | S 控制点2 终点 | S 100,200 200,300 | 绘图命令 | |
T | 平滑二次贝塞尔曲线 | T 终点 | T 400,200 | 绘图命令 | |
Z | 闭合图形 | Z | M 0,0 L 40,80 L 80,40 Z | <PathFigure IsClosed="True"/> | 关闭命令 |
<Path Stroke="Red" Data="M 0,0 C 30,0 70,100 100,100 S 170,0 200,0"/>
<Path Stroke="Black" Data="M 0,0 C 30,0 70,100 100,100 C 130,100 170,0 200,0"/>
<Path Stroke="Red" Data="M 0,200 Q 100,0 200,200 T 400,200"/>
<Path Stroke="Black" Data="M 0,0 C 30,0 70,100 100,100 C 130,100 170,0 200,0"/>
使用Path剪裁界面元素
实际工作中经常会遇到制作不规则窗体或者控件的需求,WPF在这方面做了良好的支持,仅需使窗体或控件的Clip属性就可以轻松做到。
<Window x:Class="WPFLearn.DrawAndAnimation.ClipPath"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ClipPath" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button x:Name="clipBtn" Click="ClipBtn_OnClick" Height="25" Content="Clip"/>
<Path Visibility="Hidden" x:Name="clipPath" Data="M 55,100 A 50,50 0 1 1 100,60 A 110,95 0 0 1 200,60 A 50,50 0 1 1 250,100 A 110,95 0 1 1 55,100 Z"/>
</Grid>
</Window>
private void ClipBtn_OnClick(object sender, RoutedEventArgs e)
{
this.Clip = this.clipPath.Data;
}