了解如何绘制椭圆、矩形、多边形和路径等形状。 Path 类是在 XAML UI 中可视化基于矢量的相当复杂的绘图语言的方法;例如,可以绘制贝塞尔曲线。
两组类在 XAML UI 中定义空间区域: 形状 类和 Geometry 类。 这些类之间的主要区别在于,Shape 关联有一个画笔,并且可以渲染到屏幕上,而 Geometry 仅仅定义了一块空间,且不会被渲染,除非它可以为另一个 UI 属性提供信息。 可以将 形状 视为 UIElement ,其边界由 Geometry 定义。 本主题主要介绍 Shape 类。
形状类为 Line、椭圆、矩形、多边形、折线和路径。 路径 很有趣,因为它可以定义任意几何图形,而 Geometry 类在此处涉及,因为这是定义 Path 部分的一种方法。
形状的填充和描边
要使 形状 呈现到应用画布,必须将 Brush 与其关联。 将形状的Fill属性设置为所需的画笔。 有关画笔的详细信息,请参阅 “使用画笔”。
形状还可以有一个笔划,这是在形状的外围周围绘制的线条。 笔划还需要定义其外观的画笔,并且应该具有 StrokeThickness 的非零值。 StrokeThickness 是一个属性,用于定义形状边缘周围的外围粗细。 如果未为 Stroke 指定画笔值,或者将 StrokeThickness 设置为 0,则不会绘制形状周围的边框。
椭圆形
椭圆形是一个具有弯曲周长的形状。 若要创建基本椭圆,请为椭圆指定宽度、高度和用于填充的画刷。
下一个示例创建宽度为 200 且高度为 200 的椭圆,并使用钢蓝色彩色 SolidColorBrush 作为填充。
<Ellipse Fill="SteelBlue" Height="200" Width="200" />
var ellipse1 = new Ellipse();
ellipse1.Fill = new SolidColorBrush(Colors.SteelBlue);
ellipse1.Width = 200;
ellipse1.Height = 200;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(ellipse1);
下面是呈现的 椭圆。
在这种情况下,椭圆是大多数人会考虑的圆,但这就是在 XAML 中声明圆形的方式:使用宽度和高度相等的椭圆。
当 椭圆 定位在 UI 布局中时,其大小假定与具有该 宽度 和 高度的矩形相同;外围外部的区域没有呈现,但仍是其布局槽大小的一部分。
一组 6 个椭圆 元素是 ProgressRing 控件的控件模板的一部分,2 个同心 椭圆 元素是 RadioButton 的一部分。
矩形
矩形是一个四面形状,其对边相等。 若要创建基本 矩形,请指定 宽度、 高度和 填充。
您可以将矩形的角变圆。 若要创建圆角,请指定 RadiusX 和 RadiusY 属性的值。 这些属性指定定义角曲线的椭圆的 x 轴和 y 轴。 RadiusX 允许的最大值为 Width 除以 2,RadiusY 的最大允许值为 Height 除以 2。
下一个示例创建宽度为 200 且高度为 100 的矩形。 它使用 SolidColorBrush 的 Blue 值作为其 Fill,并使用 Black 值的 SolidColorBrush 作为其 Stroke。 我们将 StrokeThickness 设置为 3。 我们将 RadiusX 属性设置为 50,RadiusY 属性设置为 10,该属性提供矩形圆角。
<Rectangle Fill="Blue"
Width="200"
Height="100"
Stroke="Black"
StrokeThickness="3"
RadiusX="50"
RadiusY="10" />
var rectangle1 = new Rectangle();
rectangle1.Fill = new SolidColorBrush(Colors.Blue);
rectangle1.Width = 200;
rectangle1.Height = 100;
rectangle1.Stroke = new SolidColorBrush(Colors.Black);
rectangle1.StrokeThickness = 3;
rectangle1.RadiusX = 50;
rectangle1.RadiusY = 10;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(rectangle1);
下面是呈现的 矩形。
对于 UI 定义,在某些情况下,边框可能更合适,而不是使用矩形。 如果打算围绕其他内容创建矩形形状,最好使用 边框 ,因为它可以包含子内容,并且会自动调整该内容的大小,而不是像 矩形 那样使用固定尺寸的高度和宽度。 如果您设置了CornerRadius 属性,Border 就可以有圆角。
另一方面, 矩形 可能是控件组合的更好选择。 许多控件模板中都可以看到 矩形,因为它用作可聚焦控件的“FocusVisual”部件。 每当控件处于“焦点”视觉状态时,此矩形就可见,在其他状态中隐藏。
Polygon
多边形是一个形状,其边界由任意数目的点定义。 边界是通过将一条线从一个点连接到下一个点来创建的,最后一个点连接到第一个点。 Points 属性定义构成边界的点的集合。 在 XAML 中,使用逗号分隔的列表定义点。 在代码隐藏中,使用 PointCollection 来定义点,并将每个点作为 Point 对象添加到集合中。
无需显式声明点,以便起点和终点都指定为相同的 Point 值。 多边形的呈现逻辑假定你正在定义封闭的形状,并将终点隐式连接到起点。
下一个示例创建一个多边形,其中 4 个点设置为(10,200),(60,140)(130,140)以及(180,200)。 它的 填充 使用 SolidColorBrush 的 LightBlue 值,并且没有 描边 值,因此它没有外围轮廓。
<Polygon Fill="LightBlue"
Points="10,200,60,140,130,140,180,200" />
var polygon1 = new Polygon();
polygon1.Fill = new SolidColorBrush(Colors.LightBlue);
var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polygon1.Points = points;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polygon1);
下面是呈现的 多边形。
小窍门
对于声明形状顶点以外的方案, 点 值通常用作 XAML 中的类型。 例如, Point 是触摸事件数据的一部分,因此你可以确切地知道触摸操作在坐标空间中的发生位置。 有关 Point 以及如何在 XAML 或代码中使用 Point 的详细信息,请参阅 Point 的 API 参考主题。
行
线条只是在坐标空间中的两个点之间绘制的线条。 线条将忽略为 Fill 提供的任何值,因为它没有内部空间。 对于 Line,请确保为 Stroke 和 StrokeThickness 属性指定值,否则 Line 不会呈现。
不使用点值来指定线形状,而是对 X1、Y1、X2 和 Y2 使用离散的 Double 值。 这为水平线或垂直线启用最小标记。 例如, <Line Stroke="Red" X2="400"/> 定义长度为 400 像素的水平线。 其他 X 和 Y 属性默认为 0,因此就坐标而言,此 XAML 将绘制一条从(0,0)到(400,0)的线。 然后,如果希望它从 (0,0) 以外的某个点开始,则可以使用 TranslateTransform 移动整个 线条。
<Line Stroke="Red" X2="400"/>
var line1 = new Line();
line1.Stroke = new SolidColorBrush(Colors.Red);
line1.X2 = 400;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(line1);
折线
折线类似于多边形,该多边形的边界由一组点定义,但折线中的最后一个点未连接到第一个点。
如果指定Polyline的Fill,Fill将绘制形状的内部空间,即使为Points设置的起点和终点不相交也是如此。 如果未指定填充,那么折线就类似于在指定了多个独立的Line元素时,每个连续线段的起点和终点相交时所呈现的效果。
与 多边形一样, Points 属性定义构成边界的点的集合。 在 XAML 中,使用逗号分隔的列表定义点。 在后台代码中,你使用 PointCollection 来定义点,并将每个单独的点作为 Point 结构添加到集合中。
本示例创建一个折线,其中四个点设置为(10,200)、(60,140)、(130,140)和(180,200)。
已定义笔划,但未定义填充。
<Polyline Stroke="Black"
StrokeThickness="4"
Points="10,200,60,140,130,140,180,200" />
var polyline1 = new Polyline();
polyline1.Stroke = new SolidColorBrush(Colors.Black);
polyline1.StrokeThickness = 4;
var points = new PointCollection();
points.Add(new Windows.Foundation.Point(10, 200));
points.Add(new Windows.Foundation.Point(60, 140));
points.Add(new Windows.Foundation.Point(130, 140));
points.Add(new Windows.Foundation.Point(180, 200));
polyline1.Points = points;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot>
layoutRoot.Children.Add(polyline1);
下面是显示的 折线。 请注意,第一个和最后一个点不是由 笔划 轮廓连接的,因为它们位于 多边形中。
路径
路径是最通用的形状,因为你可以使用它来定义任意几何图形。 但随着这种多功能性,复杂性也随之而来。 现在让我们看看如何在 XAML 中创建基本 路径 。
使用 Data 属性定义路径的几何图形。 设置 数据有两种方法:
- 可以在 XAML 中为 数据 设置字符串值。 在此表格中,Path.Data 值采用用于图形的序列化格式。 此值在首次建立之后,通常不会以字符串形式进行编辑。 而是使用设计工具,使你能够在设计或绘制图面上的隐喻中工作。 然后保存或导出输出,这为你提供了带有 Path.Data 信息的 XAML 文件或 XAML 字符串片段。
- 可以将 Data 属性设置为单个 Geometry 对象。 这可以在代码或 XAML 中完成。 单个 Geometry 通常是 GeometryGroup,它充当一个容器,可将多个几何定义组合到单个对象中,以用于对象模型。 执行此操作的最常见原因是,你想使用一个或多个可以被定义为 PathFigure 的段值的曲线和复杂形状,例如 BezierSegment。
此示例演示了一个路径,该 路径 可能是使用 Blend for Visual Studio 生成几个矢量形状,然后将结果保存为 XAML。 总 路径 由贝塞尔曲线段和线段组成。 该示例主要用于提供 Path.Data 序列化格式中存在哪些元素以及数字所表示的内容的一些示例。
此 数据 以移动命令开头,由“M”指示,该命令为路径建立绝对起点。
第一段是一条立方贝塞尔曲线,它从(100,200)开始并在(400,175)结束,而通过使用两个控制点(100,25)和(400,350)绘制。 此段由 数据 属性字符串中的“C”命令指示。
第二段以绝对水平线命令“H”开头,它指定从前面的子路径终结点 (400,175) 绘制到新终结点 (280,175)的线条。 因为它是水平线命令,因此指定的值为 x 坐标。
<Path Stroke="DarkGoldenRod"
StrokeThickness="3"
Data="M 100,200 C 100,25 400,350 400,175 H 280" />
下面是渲染的Path。
下一个示例演示了我们讨论的其他技术的用法:GeometryGroup 具有 PathGeometry。 本示例演示了一些可用作 PathGeometry 一部分的组成几何类型:PathFigure 和可成为 PathFigure.Segments 中段的各种元素。
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup>
<RectangleGeometry Rect="50,5 100,10" />
<RectangleGeometry Rect="5,5 95,180" />
<EllipseGeometry Center="100, 100" RadiusX="20" RadiusY="30"/>
<RectangleGeometry Rect="50,175 100,10" />
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="true" StartPoint="50,50">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="75,300" Point2="125,100" Point3="150,50"/>
<BezierSegment Point1="125,300" Point2="75,100" Point3="50,50"/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
var path1 = new Microsoft.UI.Xaml.Shapes.Path();
path1.Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 204, 204, 255));
path1.Stroke = new SolidColorBrush(Colors.Black);
path1.StrokeThickness = 1;
var geometryGroup1 = new GeometryGroup();
var rectangleGeometry1 = new RectangleGeometry();
rectangleGeometry1.Rect = new Rect(50, 5, 100, 10);
var rectangleGeometry2 = new RectangleGeometry();
rectangleGeometry2.Rect = new Rect(5, 5, 95, 180);
geometryGroup1.Children.Add(rectangleGeometry1);
geometryGroup1.Children.Add(rectangleGeometry2);
var ellipseGeometry1 = new EllipseGeometry();
ellipseGeometry1.Center = new Point(100, 100);
ellipseGeometry1.RadiusX = 20;
ellipseGeometry1.RadiusY = 30;
geometryGroup1.Children.Add(ellipseGeometry1);
var pathGeometry1 = new PathGeometry();
var pathFigureCollection1 = new PathFigureCollection();
var pathFigure1 = new PathFigure();
pathFigure1.IsClosed = true;
pathFigure1.StartPoint = new Windows.Foundation.Point(50, 50);
pathFigureCollection1.Add(pathFigure1);
pathGeometry1.Figures = pathFigureCollection1;
var pathSegmentCollection1 = new PathSegmentCollection();
var pathSegment1 = new BezierSegment();
pathSegment1.Point1 = new Point(75, 300);
pathSegment1.Point2 = new Point(125, 100);
pathSegment1.Point3 = new Point(150, 50);
pathSegmentCollection1.Add(pathSegment1);
var pathSegment2 = new BezierSegment();
pathSegment2.Point1 = new Point(125, 300);
pathSegment2.Point2 = new Point(75, 100);
pathSegment2.Point3 = new Point(50, 50);
pathSegmentCollection1.Add(pathSegment2);
pathFigure1.Segments = pathSegmentCollection1;
geometryGroup1.Children.Add(pathGeometry1);
path1.Data = geometryGroup1;
// When you create a XAML element in code, you have to add
// it to the XAML visual tree. This example assumes you have
// a panel named 'layoutRoot' in your XAML file, like this:
// <Grid x:Name="layoutRoot">
layoutRoot.Children.Add(path1);
这里是已呈现的路径。
使用 PathGeometry 可能比填充 Path.Data 字符串更具可读性。 另一方面, Path.Data 使用与可缩放矢量图形(SVG)图像路径定义兼容的语法,因此它对于从 SVG 移植图形或作为 Blend 等工具的输出可能很有用。
UWP 和 WinUI 2
重要
本文中的信息和示例是针对使用 Windows App SDK 和 WinUI 3 的应用优化的,但通常适用于使用 WinUI 2 的 UWP 应用。 有关特定于平台的信息和示例,请参阅 UWP API 参考。
本部分包含在 UWP 或 WinUI 2 应用中使用该控件所需的信息。
这些形状的 API 存在于 Windows.UI.Xaml.Shapes 命名空间中。