WPF 中的形状和基本绘图概述

本主题概述如何使用 Shape 对象绘图。 Shape 是一种允许您在屏幕中绘制形状的 UIElement 类型。 由于它们是 UI 元素,因此 Shape 对象可以在 Panel 元素和大多数控件中使用。

Windows Presentation Foundation (WPF) 提供了对图形和呈现服务的若干层访问。 在顶层,Shape 对象很容易使用,并且提供了许多有用功能,例如布局和参与 Windows Presentation Foundation (WPF) 事件系统。

本主题包括下列各节。

  • 形状对象
  • 使用 Path 和 Geometry
  • 绘制形状
  • 可拉伸形状
  • 变换形状
  • 相关主题

形状对象

WPF 提供了许多易于使用的 Shape 对象。 所有形状对象都是从 Shape 类继承的。 可用的 Shape 对象包括 EllipseLinePathPolygonPolylineRectangleShape 对象共享以下通用属性。

  • Stroke:说明如何绘制形状的轮廓。

  • StrokeThickness:说明形状轮廓的粗细。

  • Fill:说明如何绘制形状的内部。

  • 用于指定坐标和顶点的数据属性,以与设备无关的像素来度量。

由于形状对象派生于 UIElement,因此可以在面板和大多数控件中使用。 Canvas 面板是用于创建复杂绘图的特别理想的选择,因为它支持对其子对象的绝对定位。

使用 Line 类可以在两个点之间绘制一条直线。 下面的示例演示了几种指定线条坐标和描边属性的方法。

<Canvas Height="300" Width="300">

  <!-- Draws a diagonal line from (10,10) to (50,50). -->
  <Line
    X1="10" Y1="10"
    X2="50" Y2="50"
    Stroke="Black"
    StrokeThickness="4" />

  <!-- Draws a diagonal line from (10,10) to (50,50)
       and moves it 100 pixels to the right. -->
  <Line
    X1="10" Y1="10"
    X2="50" Y2="50"
    StrokeThickness="4"
    Canvas.Left="100">
    <Line.Stroke>
      <RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5">
        <RadialGradientBrush.GradientStops>
          <GradientStop Color="Red" Offset="0" />
          <GradientStop Color="Blue" Offset="0.25" />
        </RadialGradientBrush.GradientStops>
      </RadialGradientBrush>
    </Line.Stroke>
  </Line>

  <!-- Draws a horizontal line from (10,60) to (150,60). -->
  <Line
     X1="10" Y1="60"
     X2="150" Y2="60"
     Stroke="Black"
     StrokeThickness="4"/>

</Canvas>

' Add a Line Element
Dim myLine As New Line()
myLine.Stroke = Brushes.LightSteelBlue
myLine.X1 = 1
myLine.X2 = 50
myLine.Y1 = 1
myLine.Y2 = 50
myLine.HorizontalAlignment = HorizontalAlignment.Left
myLine.VerticalAlignment = VerticalAlignment.Center
myLine.StrokeThickness = 2
myGrid.Children.Add(myLine)

// Add a Line Element
myLine = new Line();
myLine.Stroke = System.Windows.Media.Brushes.LightSteelBlue;
myLine.X1 = 1;
myLine.X2 = 50;
myLine.Y1 = 1;
myLine.Y2 = 50;
myLine.HorizontalAlignment = HorizontalAlignment.Left;
myLine.VerticalAlignment = VerticalAlignment.Center;
myLine.StrokeThickness = 2;
myGrid.Children.Add(myLine);

// Add a Line Element
myLine = gcnew Line();
myLine->Stroke = Brushes::LightSteelBlue;
myLine->X1 = 1;
myLine->X2 = 50;
myLine->Y1 = 1;
myLine->Y2 = 50;
myLine->HorizontalAlignment = HorizontalAlignment::Left;
myLine->VerticalAlignment = VerticalAlignment::Center;
myLine->StrokeThickness = 2;
myGrid->Children->Add(myLine);

下图显示了所呈现的 Line

直线图示

虽然 Line 类提供了 Fill 属性,但设置该属性无效,因为 Line 没有区域。

另一个常用形状是 Ellipse。 通过定义形状的 WidthHeight 属性来创建 Ellipse。 若要绘制一个圆,请指定一个其 WidthHeight 值相等的 Ellipse

        <Ellipse
        Fill="Yellow"
        Height="100"
        Width="200"
        StrokeThickness="2"
        Stroke="Black"/>


Imports Microsoft.VisualBasic
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Shapes

Namespace SDKSample
    Partial Public Class SetBackgroundColorOfShapeExample
        Inherits Page
        Public Sub New()
            ' Create a StackPanel to contain the shape.
            Dim myStackPanel As New StackPanel()

            ' Create a red Ellipse.
            Dim myEllipse As New Ellipse()

            ' Create a SolidColorBrush with a red color to fill the 
            ' Ellipse with.
            Dim mySolidColorBrush As New SolidColorBrush()

            ' Describes the brush's color using RGB values. 
            ' Each value has a range of 0-255.
            mySolidColorBrush.Color = Color.FromArgb(255, 255, 255, 0)
            myEllipse.Fill = mySolidColorBrush
            myEllipse.StrokeThickness = 2
            myEllipse.Stroke = Brushes.Black

            ' Set the width and height of the Ellipse.
            myEllipse.Width = 200
            myEllipse.Height = 100

            ' Add the Ellipse to the StackPanel.
            myStackPanel.Children.Add(myEllipse)

            Me.Content = myStackPanel
        End Sub

    End Class
End Namespace
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SDKSample
{
    public partial class SetBackgroundColorOfShapeExample : Page
    {
        public SetBackgroundColorOfShapeExample()
        {
            // Create a StackPanel to contain the shape.
            StackPanel myStackPanel = new StackPanel();

            // Create a red Ellipse.
            Ellipse myEllipse = new Ellipse();

            // Create a SolidColorBrush with a red color to fill the 
            // Ellipse with.
            SolidColorBrush mySolidColorBrush = new SolidColorBrush();

            // Describes the brush's color using RGB values. 
            // Each value has a range of 0-255.
            mySolidColorBrush.Color = Color.FromArgb(255, 255, 255, 0);
            myEllipse.Fill = mySolidColorBrush;
            myEllipse.StrokeThickness = 2;
            myEllipse.Stroke = Brushes.Black;

            // Set the width and height of the Ellipse.
            myEllipse.Width = 200;
            myEllipse.Height = 100;

            // Add the Ellipse to the StackPanel.
            myStackPanel.Children.Add(myEllipse);

            this.Content = myStackPanel;
        }

    }
}

下图显示了一个已呈现 Ellipse 的示例。

椭圆图示

使用 Path 和 Geometry

使用 Path 类可以绘制曲线和复杂形状。 这些曲线和形状使用 Geometry 对象来说明 若要使用 Path,请创建一个 Geometry 并使用它来设置 Path 对象的 Data 属性。

可以从各种 Geometry 对象中进行选择。 LineGeometryRectangleGeometryEllipseGeometry 类说明了相对简单的形状。 若要创建更复杂的形状或创建曲线,请使用 PathGeometry

PathGeometry 和 PathSegment

PathGeometry 对象由一个或多个 PathFigure 对象组成;每个 PathFigure 代表一个不同的“图形”或形状。 每个 PathFigure 自身又由一个或多个 PathSegment 对象组成,每个对象均代表图形或形状的已连接部分。 Segment 类型包括 LineSegmentBezierSegmentArcSegment

在下面的示例中,使用一个 Path 来绘制二次方贝塞尔曲线。

<Path Stroke="Black" StrokeThickness="1">
  <Path.Data>
    <PathGeometry>
      <PathGeometry.Figures>
        <PathFigureCollection>
          <PathFigure StartPoint="10,100">
            <PathFigure.Segments>
              <PathSegmentCollection>
                <QuadraticBezierSegment Point1="200,200" Point2="300,100" />
              </PathSegmentCollection>
            </PathFigure.Segments>
          </PathFigure>
        </PathFigureCollection>
      </PathGeometry.Figures>
    </PathGeometry>
  </Path.Data>
</Path>

下图显示了所呈现的形状。

路径图示

有关 PathGeometry 和其他 Geometry 类的更多信息,请参见 Geometry 概述

XAML 缩写语法

在Extensible Application Markup Language (XAML) 中,还可以使用一种特殊的缩写语法来说明 Path。 在下面的示例中,使用缩写语法来绘制一个复杂形状。

<Path Stroke="DarkGoldenRod" StrokeThickness="3" 
Data="M 100,200 C 100,25 400,350 400,175 H 280" />

下面的图像显示了一个已呈现的 Path

路径图示

Data 特性字符串以“moveto”命令开头(由 M 指示),它为 Canvas 的坐标系统中的路径建立一个起点。 Path 数据参数区分大小写。 大写的 M 指示新的当前点的绝对位置。 小写 m 则指示相对坐标。 第一段是一个三次方贝塞尔曲线,该曲线从 (100,200) 开始,在 (400,175) 结束,使用 (100,25) 和 (400,350) 这两个控制点绘制。 此段由 Data 特性字符串中的 C 命令指示。 同样,大写的 C 指示绝对路径;小写的 c 则指示相对路径。

第二段以绝对水平“lineto”命令 H 开头,它指定绘制一条从前面的子路径的终结点 (400,175) 到新终结点 (280,175) 的直线。 由于它是一个水平“lineto”命令,因此指定的值是 x 坐标。

有关完整的路径语法,请参见 Data 参考内容和如何:使用 PathGeometry 创建形状

绘制形状

Brush 对象用于绘制形状的 StrokeFill。 在下面的示例中,指定了 Ellipse 的描边和填充。 请注意,画笔属性的有效输入可以是关键字或十六进制颜色值。 有关可用的颜色关键字的更多信息,请参见 System.Windows.Media 命名空间中 Colors 类的属性。

<Canvas Background="LightGray"> 
   <Ellipse
      Canvas.Top="50"
      Canvas.Left="50"
      Fill="#FFFFFF00"
      Height="75"
      Width="75"
      StrokeThickness="5"
      Stroke="#FF0000FF"/>
</Canvas>

下图显示了所呈现的 Ellipse

椭圆

您也可以使用属性元素语法显式创建一个 SolidColorBrush 对象,以使用纯色绘制形状。

<!-- This polygon shape uses pre-defined color values for its Stroke and
     Fill properties. 
     The SolidColorBrush's Opacity property affects the fill color in 
     this case by making it slightly transparent (opacity of 0.4) so 
     that it blends with any underlying color. -->
   
<Polygon
    Points="300,200 400,125 400,275 300,200"
    Stroke="Purple" 
    StrokeThickness="2">
    <Polygon.Fill>
       <SolidColorBrush Color="Blue" Opacity="0.4"/>
    </Polygon.Fill>
</Polygon>

下图显示呈现的形状。

SolidColorBrush 图示

还可以绘制形状的带有渐变、图像、图案等效果的描边或填充。 有关更多信息,请参见 使用纯色和渐变进行绘制概述

可拉伸形状

LinePathPolygonPolylineRectangle 类都有一个 Stretch 属性。 该属性确定如何拉伸 Shape 对象的内容(要绘制的形状)以填充 Shape 对象的布局空间。 Shape 对象的布局空间是布局系统分配给 Shape(根据显式的 WidthHeight 设置,或其 HorizontalAlignmentVerticalAlignment 设置)的空间量。 有关 Windows Presentation Foundation 中的布局的更多信息,请参见布局系统概述。

Stretch 属性使用以下值之一:

  • None:不拉伸 Shape 对象的内容。

  • Fill:拉伸 Shape 对象的内容以填充其布局空间。 不保留长宽比。

  • Uniform:尽可能地拉伸 Shape 对象的内容以填充其布局空间,同时保留其原始长宽比。

  • UniformToFill:完全拉伸 Shape 对象的内容以填充其布局空间,同时保留其原始长宽比。

请注意,在拉伸 Shape 对象的内容时,会在拉伸之后绘制 Shape 对象的轮廓。

在下面的示例中,使用一个 Polygon 从 (0,0) 到 (0,1),再到 (1,1) 绘制一个非常小的三角形。 Polygon 对象的 WidthHeight 设置为 100,其拉伸属性设置为 Fill。 结果是,将拉伸 Polygon 对象的内容(三角形)以填充更大的空间。

...
<Polygon
  Points="0,0 0,1 1,1"
  Fill="Blue"
  Width="100"
  Height="100"
  Stretch="Fill"
  Stroke="Black"
  StrokeThickness="2" />
...

...
PointCollection myPointCollection = new PointCollection();
myPointCollection.Add(new Point(0,0));
myPointCollection.Add(new Point(0,1));
myPointCollection.Add(new Point(1,1));

Polygon myPolygon = new Polygon();
myPolygon.Points = myPointCollection;
myPolygon.Fill = Brushes.Blue;
myPolygon.Width = 100;
myPolygon.Height = 100;
myPolygon.Stretch = Stretch.Fill;
myPolygon.Stroke = Brushes.Black;
myPolygon.StrokeThickness = 2;
...

变换形状

Transform 类提供了在二维平面中变换形状的方法。 不同类型的变换包括旋转 (RotateTransform)、缩放 (ScaleTransform)、斜切 (SkewTransform) 和转换 (TranslateTransform)。

经常应用于形状的变换操作是旋转。 若要旋转形状,请创建一个 RotateTransform 并指定其 Angle。 45 度的 Angle 将元素沿顺时针方向旋转 45 度;90 度将元素沿顺时针方向旋转 90 度;依此类推。 如果您要控制元素的旋转点,请设置 CenterXCenterY 属性。 这些属性值以要变换元素的坐标空间表示。 CenterXCenterY 具有默认值零。 最后,将 RotateTransform 应用于该元素。 如果您不希望变形影响到布局,请设置形状的 RenderTransform 属性。

在下面的示例中,使用 RotateTransform 将形状围绕其左上角 (0,0) 旋转 45 度。

<!-- Rotates the Polyline 45 degrees about the point (0,0). -->
<Polyline Points="25,25 0,50 25,75 50,50 25,25 25,0" 
  Stroke="Blue" StrokeThickness="10"
  Canvas.Left="75" Canvas.Top="50">
  <Polyline.RenderTransform>
    <RotateTransform CenterX="0" CenterY="0" Angle="45" />
  </Polyline.RenderTransform>
</Polyline>

在下一个示例中,另一个形状将旋转 45 度,但这一次围绕点 (25,50) 进行旋转。

<!-- Rotates the Polyline 45 degrees about its center. -->
<Polyline 
  Points="25,25 0,50 25,75 50,50 25,25 25,0" 
  Stroke="Blue" StrokeThickness="10"
  Canvas.Left="75" Canvas.Top="50"
  RenderTransformOrigin="0.5,0.5">
  <Polyline.RenderTransform>
    <RotateTransform Angle="45" />
  </Polyline.RenderTransform>
</Polyline>

下图显示了应用这两种变形的结果。

以不同中心点进行的 45 度旋转

在上一个示例中,向每个形状对象应用了一次变形。 若要向一个形状(或任何其他 UI 元素)应用多次变形,请使用 TransformGroup

请参见

概念

优化性能:二维图形和图像处理

使用纯色和渐变进行绘制概述

Geometry 概述

演练:开始使用 WPF

动画概述