繪製圖形Draw shapes

了解如何繪製圖形,例如橢圓形、矩形、多邊形以及路徑。Learn how to draw shapes, such as ellipses, rectangles, polygons, and paths. Path 類別是在 XAML UI 中視覺化非常複雜之向量繪製語言的方法,例如,繪製貝茲曲線。The Path class is the way to visualize a fairly complex vector-based drawing language in a XAML UI; for example, you can draw Bezier curves.

重要 APIPath 類別Windows.UI.Xaml.Shapes 命名空間Windows.UI.Xaml.Media 命名空間Important APIs: Path class, Windows.UI.Xaml.Shapes namespace, Windows.UI.Xaml.Media namespace

有兩組類別可定義 XAML UI 的空間區域:Shape 類別和 Geometry 類別。Two sets of classes define a region of space in XAML UI: Shape classes and Geometry classes. 這兩組類別的主要差異,在於 Shape 有一個相關聯的筆刷,而且可以轉譯到螢幕上;Geometry 只定義空間區域,而且除非有助於提供資訊給其他 UI 屬性,否則並不會進行轉譯。The main difference between these classes is that a Shape has a brush associated with it and can be rendered to the screen, and a Geometry simply defines a region of space and is not rendered unless it helps contribute information to another UI property. 您可以將 Shape 想成是一個 UIElement,且由 Geometry 定義其界限。You can think of a Shape as a UIElement with its boundary defined by a Geometry. 本主題主要涵蓋 Shape 類別。This topic covers mainly the Shape classes.

Shape 類別有 LineEllipseRectanglePolygonPolyline 以及 PathThe Shape classes are Line, Ellipse, Rectangle, Polygon, Polyline, and Path. Path 很有趣,因為它可以定義任意幾何圖形,而且這裡還涉及 Geometry 類別,因為這是定義 Path 組件的其中一種方法。Path is interesting because it can define an arbitrary geometry, and the Geometry class is involved here because that's one way to define the parts of a Path.

圖形的填滿與筆觸Fill and Stroke for shapes

若要將 Shape 轉譯到應用程式畫布,您必須使其與 Brush 建立關聯。For a Shape to render to the app canvas, you must associate a Brush with it. ShapeFill 屬性設成所需的 BrushSet the Fill property of the Shape to the Brush you want. 如需關於筆刷的資訊,請參閱使用筆刷For more info about brushes, see Using brushes.

Shape 也可以包含 Stroke,這是在圖形周邊繪製的線條。A Shape can also have a Stroke, which is a line that is drawn around the shape's perimeter. Stroke 也需要 Brush 來定義外觀,且 StrokeThickness 應為非零的值。A Stroke also requires a Brush that defines its appearance, and should have a non-zero value for StrokeThickness. StrokeThickness 是定義圖形邊緣之周邊厚度的屬性。StrokeThickness is a property that defines the perimeter's thickness around the shape edge. 如果您沒有為 Stroke 指定 Brush 值,或是將 StrokeThickness 設為 0,則不會繪製圖形周圍的框線。If you don't specify a Brush value for Stroke, or if you set StrokeThickness to 0, then the border around the shape is not drawn.

橢圓形Ellipse

Ellipse 是周邊為弧形的圖形。An Ellipse is a shape with a curved perimeter. 若要建立基本的 Ellipse,請指定 FillWidthHeight 以及 BrushTo create a basic Ellipse, specify a Width, Height, and a Brush for the Fill.

以下範例會建立 Width 200 與 Height 200 的一個 Ellipse,並使用 SteelBlue 色的 SolidColorBrush 作為其 FillThe next example creates an Ellipse with a Width of 200 and a Height of 200, and uses a SteelBlue colored SolidColorBrush as its Fill.

<Ellipse Fill="SteelBlue" Height="200" Width="200" />
var ellipse1 = new Ellipse();
ellipse1.Fill = new SolidColorBrush(Windows.UI.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);

以下是經過轉譯的 EllipseHere's the rendered Ellipse.

經過轉譯的橢圓形。

大多數人會將這裡的 Ellipse 視為圓形,事實上您在 XAML 宣告圓形的方式正是:使用相等 WidthHeightEllipseIn this case the Ellipse is what most people would consider a circle, but that's how you declare a circle shape in XAML: use an Ellipse with equal Width and Height.

Ellipse 置於 UI 配置中時,會將其大小假設為與該 WidthHeight 的矩形相同;周邊外圍的區域不會轉譯,但仍是其配置位置大小的一部分。When an Ellipse is positioned in a UI layout, its size is assumed to be the same as a rectangle with that Width and Height; the area outside the perimeter does not have rendering but still is part of its layout slot size.

一組 6 個 Ellipse 元素屬於 ProgressRing 控制項的控制項範本,而 2 個同心 Ellipse 元素則屬於 RadioButtonA set of 6 Ellipse elements are part of the control template for the ProgressRing control, and 2 concentric Ellipse elements are part of a RadioButton.

矩形Rectangle

Rectangle 是對應邊相等的四邊形。A Rectangle is a four-sided shape with its opposite sides being equal. 若要建立基本的 Rectangle,請指定 WidthHeight 以及 FillTo create a basic Rectangle, specify a Width, a Height, and a Fill.

您可以使 Rectangle 的四角變成圓角。You can round the corners of a Rectangle. 若要建立圓角,請指定 RadiusXRadiusY 屬性的值。To create rounded corners, specify a value for the RadiusX and RadiusY properties. 這些屬性指定橢圓形的 x-軸與 y-軸,進而定義圓角的弧形。These properties specify the x-axis and y-axis of an ellipse that defines the curve of the corners. RadiusX 允許的最大值是 Width 除以二,RadiusY 允許的最大值是 Height 除以二。The maximum allowed value of RadiusX is the Width divided by two and the maximum allowed value of RadiusY is the Height divided by two.

以下範例會建立 Width 200 與 Height 100 的 RectangleThe next example creates a Rectangle with a Width of 200 and a Height of 100. 它的 Fill 使用 SolidColorBrushBlue 值,Stroke 使用 SolidColorBrushBlack 值。It uses a Blue value of SolidColorBrush for its Fill and a Black value of SolidColorBrush for its Stroke. 我們將 StrokeThickness 設成 3。We set the StrokeThickness to 3. 同時並將 RadiusX 屬性設成 50,將 RadiusY 屬性設成 10,就會使 Rectangle 變成圓角。We set the RadiusX property to 50 and the RadiusY property to 10, which gives the Rectangle rounded corners.

<Rectangle Fill="Blue"
           Width="200"
           Height="100"
           Stroke="Black"
           StrokeThickness="3"
           RadiusX="50"
           RadiusY="10" />
var rectangle1 = new Rectangle();
rectangle1.Fill = new SolidColorBrush(Windows.UI.Colors.Blue);
rectangle1.Width = 200;
rectangle1.Height = 100;
rectangle1.Stroke = new SolidColorBrush(Windows.UI.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);

以下是經過轉譯的 RectangleHere's the rendered Rectangle.

經過轉譯的矩形。

提示  :在某些情況下,UI 定義使用 Border 會比使用 Rectangle 更恰當。Tip  There are some scenarios for UI definitions where instead of using a Rectangle, a Border might be more appropriate. 如果您要在其他內容的周圍建立矩形,使用 Border 較合適,因為可以包含子內容,並且會自動沿著內容調整大小,不像 Rectangle 使用固定的高度與寬度。If your intention is to create a rectangle shape around other content, it might be better to use Border because it can have child content and will automatically size around that content, rather than using the fixed dimensions for height and width like Rectangle does. 如果設定 CornerRadius 屬性,則 Border 也有包含圓角的選項。A Border also has the option of having rounded corners if you set the CornerRadius property.

另一方面,Rectangle 或許是控制項組合較佳的選擇。On the other hand, a Rectangle is probably a better choice for control composition. Rectangle 形狀在很多控制項範本都看得到,因為它可以做為能取得焦點之控制項的 "FocusVisual" 組件。A Rectangle shape is seen in many control templates because it's used as a "FocusVisual" part for focusable controls. 只要控制項處於「取得焦點」的視覺狀態,這個矩形就會顯示,在其他狀態則會隱藏。Whenever the control is in a "Focused" visual state, this rectangle is made visible, in other states it's hidden.

多邊形Polygon

Polygon 是界限由任意數目的點所定義的形狀。A Polygon is a shape with a boundary defined by an arbitrary number of points. 建立界限的方式是以直線連接一個點到下一個點,最後一個點再連回第一個點。The boundary is created by connecting a line from one point to the next, with the last point connected to the first point. Points 屬性定義形成界限的點集合。The Points property defines the collection of points that make up the boundary. 在 XAML 中,您使用逗號分隔清單定義各個點。In XAML, you define the points with a comma-separated list. 在程式碼後置中,則是使用 PointCollection 定義點,並將每個獨立的點當成 Point 值加入集合中。In code-behind you use a PointCollection to define the points and you add each individual point as a Point value to the collection.

起點與終點不需要明確宣告,就會指定為相同的 Point 值。You don't need to explicitly declare the points such that the start point and end point are both specified as the same Point value. Polygon 的轉譯邏輯會假設您正在定義封閉的形狀,並會自動連接終點與起點。The rendering logic for a Polygon assumes that you are defining a closed shape and will connect the end point to the start point implicitly.

下一個範例建立 4 點分別設成 (10,200)(60,140)(130,140) 以及 (180,200)PolygonThe next example creates a Polygon with 4 points set to (10,200), (60,140), (130,140), and (180,200). 它的 Fill 使用 SolidColorBrushLightBlue 值,Stroke 則未包含值,因此並無周邊外框。It uses a LightBlue value of SolidColorBrush for its Fill, and has no value for Stroke so it has no perimeter outline.

<Polygon Fill="LightBlue"
         Points="10,200,60,140,130,140,180,200" />
var polygon1 = new Polygon();
polygon1.Fill = new SolidColorBrush(Windows.UI.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);

以下是經過轉譯的 PolygonHere's the rendered Polygon.

經過轉譯的多邊形。

提示  :在宣告圖形頂點以外的 XAML 中,Point 值通常會用來做為類型。Tip  A Point value is often used as a type in XAML for scenarios other than declaring the vertices of shapes. 例如,Point 屬於觸控事件的事件資料,因此您可以知道觸控動作在座標空間發生的確切位置。For example, a Point is part of the event data for touch events, so you can know exactly where in a coordinate space the touch action occurred. 如需有關 Point 以及如何將其使用於 XAML 或程式碼的詳細資訊,請參閱 Point 的 API 參考主題。For more info about Point and how to use it in XAML or code, see the API reference topic for Point.

線條Line

Line 只是在座標空間中兩點之間繪製的線條。A Line is simply a line drawn between two points in coordinate space. Line 會忽略提供給 Fill 的任何值,因為它沒有內部空間。A Line ignores any value provided for Fill, because it has no interior space. 對於 Line,請務必指定 Stroke 的值與 StrokeThickness 屬性,否則 Line 無法轉譯。For a Line, make sure to specify values for the Stroke and StrokeThickness properties, because otherwise the Line won't render.

您無法使用 Point 值指定 Line 圖形,而是必須使用 X1Y1X2 以及 Y2 的離散 Double 值。You don't use Point values to specify a Line shape, instead you use discrete Double values for X1, Y1, X2 and Y2. 這樣就可以使用最簡潔的標記語言來繪製水平或垂直線。This enables minimal markup for horizontal or vertical lines. 例如,<Line Stroke="Red" X2="400"/> 定義了 400 個像素長的水平線。For example, <Line Stroke="Red" X2="400"/> defines a horizontal line that is 400 pixels long. 另一個 X、Y 屬性預設為 0,因此這個 XAML 的點會繪製從 (0,0)(400,0) 的線條。The other X,Y properties are 0 by default, so in terms of points this XAML would draw a line from (0,0) to (400,0). 然後,如果您希望它從 (0,0) 以外的點開始,可以使用 TranslateTransform 移動整個 LineYou could then use a TranslateTransform to move the entire Line, if you wanted it to start at a point other than (0,0).

<Line Stroke="Red" X2="400"/>
var line1 = new Line();
line1.Stroke = new SolidColorBrush(Windows.UI.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

PolylinePolygon 類似,都是由一組點定義圖形的界限,不過 Polyline 的最後一點並不會連接第一個點。A Polyline is similar to a Polygon in that the boundary of the shape is defined by a set of points, except the last point in a Polyline is not connected to the first point.

注意  :您可以在為 Polyline設定的 Points 中明確指定相同的起點與終點,但在該情況下,您大可改用 PolygonNote   You could explicitly have an identical start point and end point in the Points set for the Polyline, but in that case you probably could have used a Polygon instead.

如果指定 PolylineFillFill 就會繪製圖形的內部空間,即使設定給 PolylinePoints 的起點與終點未交叉也一樣。If you specify a Fill of a Polyline, the Fill paints the interior space of the shape, even if the start point and end point of the Points set for the Polyline do not intersect. 如果未指定 FillPolyline 會與指定數個個別 Line 元素的轉譯結果一樣,即連續線條的起點與終點會交叉。If you do not specify a Fill, then the Polyline is similar to what would have rendered if you had specified several individual Line elements where the start points and end points of consecutive lines intersected.

如同 PolygonPoints 屬性定義形成界限的點集合。As with a Polygon, the Points property defines the collection of points that make up the boundary. 在 XAML 中,您使用逗號分隔清單定義各個點。In XAML, you define the points with a comma-separated list. 在程式碼後置中,則是使用 PointCollection 定義點,並將每個獨立的點當成 Point 結構加入集合中。In code-behind, you use a PointCollection to define the points and you add each individual point as a Point structure to the collection.

此範例會建立四點分別設為 (10,200)(60,140)(130,140)(180,200)PolylineThis example creates a Polyline with four points set to (10,200), (60,140), (130,140), and (180,200). Stroke 已定義,但並非 FillA Stroke is defined but not a Fill.

<Polyline Stroke="Black"
        StrokeThickness="4"
        Points="10,200,60,140,130,140,180,200" />
var polyline1 = new Polyline();
polyline1.Stroke = new SolidColorBrush(Windows.UI.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);

以下是經過轉譯的 Polyline請注意,第一個點與最後一點並不會像在 Polygon 般以 Stroke 外框相互連接。Notice that the first and last points are not connected by the Stroke outline as they are in a Polygon.

經過轉譯的聚合線條。

路徑Path

Path 是最多功能的 Shape,因為它可以用來定義任意幾何圖形。A Path is the most versatile Shape because you can use it to define an arbitrary geometry. 但是多功能性也意謂著複雜度較高。But with this versatility comes complexity. 我們來看一下如何在 XAML 中建立基本的 PathLet's now look at how to create a basic Path in XAML.

Data 屬性定義路徑的幾何圖形。You define the geometry of a path with the Data property. 設定 Data 的技術有兩種:There are two techniques for setting Data:

  • 您可以在 XAML 中設定 Data 的字串值。You can set a string value for Data in XAML. 使用此格式時,Path.Data 值會使用圖形的序列化格式。In this form, the Path.Data value is consuming a serialization format for graphics. 這個值在最初建立後,您通常不會再以字串格式對此值做文字編輯。You typically don't text-edit this value in string form after it is first established. 而是使用可讓您在介面使用設計或以隱喻方法繪圖的設計工具。Instead, you use design tools that enable you to work in a design or drawing metaphor on a surface. 然後儲存或匯出輸出,這樣您會取得含有 Path.Data 資訊的 XAML 檔案或 XAML 字串片段。Then you save or export the output, and this gives you a XAML file or XAML string fragment with Path.Data information.
  • Data 屬性設為單一 Geometry 物件。You can set the Data property to a single Geometry object. 這可以在程式碼或在 XAML 中完成。This can be done in code or in XAML. 該單一 Geometry 通常為 GeometryGroup,可以將多個幾何定義組合成單一物件的容器以作為物件模型之用。That single Geometry is typically a GeometryGroup, which acts as a container that can composite multiple geometry definitions into a single object for purposes of the object model. 最常這樣做的理由是因為您想要使用可以定義為 PathFigureSegments 值的一或多個曲線與複合圖形,例如 BezierSegmentThe most common reason for doing this is because you want to use one or more of the curves and complex shapes that can be defined as Segments values for a PathFigure, for example BezierSegment.

這個範例顯示 Path 的產生方式,我們在此使用 Blend for Visual Studio 製作少數向量圖形,接著將結果儲存為 XAML。This example shows a Path that might have resulted from using Blend for Visual Studio to produce just a few vector shapes and then saving the result as XAML. Path 共包含一段貝茲曲線與一段直線。The total Path consists of a Bezier curve segment and a line segment. 這個範例是為了讓您了解 Path.Data 序列化格式所含的元素,以及數字代表的意義。The example is mainly intended to give you some examples of what elements exist in the Path.Data serialization format and what the numbers represent.

Data 由移動命令 (以 "M" 表示) 開始進行,該命令會建立路徑的絕對起點。This Data begins with the move command, indicated by "M", which establishes an absolute start point for the path.

第一段是起點為 (100,200) 而終點為 (400,175) 的貝茲立方曲線,使用兩個控制點 (100,25)(400,350) 繪製。The first segment is a cubic Bezier curve that begins at (100,200) and ends at (400,175), which is drawn by using the two control points (100,25) and (400,350). 這一段是由 Data 屬性字串中的 "C" 命令指示。This segment is indicated by the "C" command in the Data attribute string.

第二段以絕對水平線命令 "H" 開始,該命令指定一條由前面子路徑端點 (400,175) 到新端點 (280,175) 所繪製出的直線。The second segment begins with an absolute horizontal line command "H", which specifies a line drawn from the preceding subpath endpoint (400,175) to a new endpoint (280,175). 因為它是一個水平線命令,所以指定的值是一個 x 座標。Because it's a horizontal line command, the value specified is an x-coordinate.

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

以下是經過轉譯的 PathHere's the rendered Path.

簡單轉譯路徑的螢幕擷取畫面。

下個範例示範我們已討論過的另一個技術用法:GeometryGroup 搭配 PathGeometryThe next example shows a usage of the other technique we discussed: a GeometryGroup with a PathGeometry. 此範例會運用可作為 PathGeometry 一部分的一些參與幾何類型:PathFigure 和可以是 PathFigure.Segments 中區段的各種元素。This example exercises some of the contributing geometry types that can be used as part of a PathGeometry: PathFigure and the various elements that can be a segment in 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 Windows.UI.Xaml.Shapes.Path();
path1.Fill = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 204, 204, 255));
path1.Stroke = new SolidColorBrush(Windows.UI.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);

以下是經過轉譯的 PathHere's the rendered Path.

複雜轉譯路徑的螢幕擷取畫面。

使用 PathGeometry 可能會較填入 Path.Data 字串更易閱讀。Using PathGeometry may be more readable than populating a Path.Data string. 相反地,Path.Data 使用與可縮放向量圖形 (SVG) 映像路徑定義相容的語法,在從 SVG 移植圖形或自 Blend 等工具輸出時非常實用。On the other hand, Path.Data uses a syntax compatible with Scalable Vector Graphics (SVG) image path definitions so it may be useful for porting graphics from SVG, or as output from a tool like Blend.