図形の描画

楕円、矩形、多角形、パスなどの図形を描画する方法について説明します。 Path クラスは、XAML UI で非常に複雑なベクターベースの描画言語を視覚化する方法です。たとえば、ベジエ曲線を描画できます。

XAML UI に空間領域を定義するクラスのセットには、ShapeGeometry の 2 つがあります。 これらのクラスの主な違いは、Shape にブラシが関連付けられているため、画面にレンダリングできることです。Geometry は単に領域の領域を定義し、別の UI プロパティに情報を提供できない限りレンダリングされません。 Shape は、ジオメトリによって境界が定義された UIElementと考えることができます。 このトピックでは、主にShape クラスについて説明します。

Shape クラスはLine, Ellipse, Rectangle, Polygon, PolylinePathです。 Path は任意のジオメトリを定義でき、Geometry クラスは Path の部分を定義する 1 つの方法であるため、ここに関係しているため、興味深いものです。

UWP と WinUI 2

重要

この記事の情報と例は、Windows アプリ SDKWinUI 3 を使用するアプリ向けに最適化されていますが、一般に WinUI 2 を使用する UWP アプリに適用されます。 プラットフォーム固有の情報と例については、UWP API リファレンスを参照してください。

このセクションには、UWP または WinUI 2 アプリでコントロールを使用するために必要な情報が含まれています。

これらの図形の API は、Windows.UI.Xaml.Shapes 名前空間に存在します。

図形の塗りつぶしとストローク

Shape をアプリ キャンバスにレンダリングするには、Brushを関連付ける必要があります。 ShapeFill プロパティを目的のブラシに設定します。 ブラシの詳細については、「 ブラシの使用」を参照してください。

Shapeには、図形の周りに描画される線であるStrokeを含めることもできます。 Stroke には、外観を定義するブラシも必要であり、StrokeThickness には 0 以外の値が必要です。 StrokeThickness は、図形の端の周囲の境界の厚さを定義するプロパティです。 StrokeBrush 値を指定しない場合、または StrokeThickness を 0 に設定した場合、シェイプの周囲の境界線は描画されません。

楕円

Ellipseは、曲線の境界を持つ図形です。 基本的な楕円を作成するには、塗りつぶし高さ、およびブラシを指定します。

次の例では、 200、高さ 200 の楕円 を作成し、塗りつぶしとして SteelBlue 色の 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);

レンダリングされた楕円を次に示します。

A rendered Ellipse.

この場合、 楕円 はほとんどの人が円を考慮するものですが、XAML で円の図形を宣言する方法です。高さが等しい楕円を使用します。

楕円が UI レイアウトに配置されている場合、そのサイズは、その高さの矩形と同じであると見なされます。境界の外側の領域にはレンダリングはありませんが、レイアウト スロット サイズの一部です。

6 つの楕円要素のセットは ProgressRing コントロールのコントロール テンプレートの一部であり、2 つの同心楕円要素は RadioButton の一部です。

Rectangle

矩形は、反対側が等しい 4 辺の図形です。 基本的な矩形を作成するには、高さ塗りつぶしを指定します。

矩形の角を丸めることができます。 角を丸くするには、RadiusX プロパティとRadiusY プロパティの値を指定します。 これらのプロパティは、角の曲線を定義する楕円の x 軸と y 軸を指定します。 RadiusX の最大値は幅を 2 で除算し、RadiusY の最大許容値は高さ を 2 で割った値です。

次の例では、 200、高さ 100 の矩形を作成します。 塗りつぶしには Blue 値の SolidColorBrushストロークには SolidColorBrushの値を使用します。 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);

レンダリングされた矩形を次に示します。

A rendered Rectangle.

UI 定義のシナリオによっては、矩形 を使用する代わりに 境界線 の方が適切な場合があります。 他のコンテンツの周りに矩形の図形を作成する場合は、子コンテンツを持つ可能性があり、矩形のように高さと幅に固定サイズを使用するのではなく、自動的にそのコンテンツの周りにサイズを設定するため、境界線 を使用することをお勧めします。 境界 には、CornerRadiusプロパティを設定した場合に角を丸くすることもできます。

一方、矩形は、おそらくコントロールの構成に適した選択肢です。 矩形図形は、フォーカス可能なコントロールの「FocusVisual」部分として使用されるため、多くのコントロール テンプレートで見られます。 コントロールが「フォーカス」表示状態になると、この矩形は表示され、他の状態では非表示になります。

Polygon

多角形は、任意の数の点で定義された境界を持つ図形です。 境界は、ある点から次の点まで線を接続し、最後の点が最初の点に接続されることによって作成されます。 Pointsプロパティは、境界を構成するポイントのコレクションを定義します。 XAML では、コンマ区切りリストを使用してポイントを定義します。 分離コードでは、PointCollectionを使用してポイントを定義し、個々のポイントを Point 値としてコレクションに追加します。

始点と終点の両方が同じ Point 値として指定されるように、ポイントを明示的に宣言する必要はありません。 Polygon のレンダリング ロジックでは、閉じた図形を定義し、終点を始点に暗黙的に接続することを前提としています。

次の例では、4 つの点が (10,200)(60,140)(130,140)(180,200) に設定されたポリゴンを作成します。 塗りつぶしには LightBlue の値 SolidColorBrush を使用し、Stroke には値を持たないため、境界のアウトラインはありません。

<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);

レンダリングされたPolygonを次に示します。

A rendered Polygon.

ヒント

Point値は、図形の頂点を宣言する以外のシナリオで、XAML の型としてよく使用されます。 たとえば、 Point はタッチ イベントのイベント データの一部であるため、座標空間内のどこでタッチ アクションが発生したかを正確に把握できます。 Point の詳細と、それを XAML またはコードで使用する方法については、Point の API リファレンス トピックを参照してください。

ライン

Lineは、座標空間内の 2 つの点の間に描画される単なる線です。 Lineは、内部スペースがないため、塗りつぶしに指定された値を無視します。 Line の場合は、Stroke プロパティとStrokeThickness プロパティの値を指定してください。それ以外の場合はLineがレンダリングされないためです。

Lineの図形を指定するためにPoint 値を使用しません。代わりに、 X1Y1X2Y2に不連続の Double値を使用します。 これにより、水平線または垂直線のマークアップを最小限に抑えることができます。 たとえば、<Line Stroke="Red" X2="400"/> は長さ 400 ピクセルの水平線を定義します。 他の X、Y プロパティはデフォルトで 0 であるため、点に関しては、この XAML は (0,0) から (400,0) まで線を描画します。 その後、TranslateTransformを使用して、(0,0) 以外のポイントから開始する場合は、Line全体を移動できます。

<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

Polyline は、形状の境界が点のセットによって定義されるという点でPolygonに似ていますが、Polyline の最後の点が最初の点に接続されていない点が異なります。

Note

Polylineに設定された Pointsに同一の開始点と終了点を明示的に指定することもできますが、その場合は、代わりにPolygonを使用することもできたでしょう。

PolylineFill を指定すると、Polyline に設定された Pointsの始点と終点が交差していなくても、Fillは形状の内部空間をペイントします。 Fillを指定しない場合、Polylineは、連続する線の始点と終点が交差する複数の個別Line 要素を指定した場合にレンダリングされたものと似ています。

Polygonと同様に、Points プロパティは境界を構成するポイントのコレクションを定義します。 XAML では、コンマ区切りリストを使用してポイントを定義します。 分離コードでは、PointCollectionを使用してポイントを定義し、個々のポイントをPoint 構造体としてコレクションに追加します。

この例では、4 つの点を (10,200)(60,140)(130,140)(180,200) に設定してPolylineを作成します。 Strokeは定義されていますが、Fillではありません。

<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);

レンダリングされたPolylineを次に示します。 最初のポイントと最後のポイントは、Polygon内のStrokeアウトラインによって接続されていないことに注意してください。

A rendered Polyline.

Path

Pathは、任意のジオメトリを定義するために使用できるため、最も汎用性の高いShapeです。 しかし、この多様性により、複雑さが生み出されます。 次に、XAML で基本的な Path を作成する方法を見てみましょう。

Dataプロパティを使用して、パスのジオメトリを定義します。 Dataを設定するには 2 つの手法があります。

  • XAML でDataの文字列値を設定できます。 この形式では、Path.Data値はグラフィックスのシリアル化形式を使用します。 通常、この値は、最初に確立された後、文字列形式ではテキスト編集しません。 代わりに、デザイン ツールを使用して、サーフェス上のデザインまたは描画メタファーを操作できます。 次に、出力を保存またはエクスポートします。これにより、Path.Data 情報を含む XAML ファイルまたは XAML 文字列フラグメントが提供されます。
  • Data プロパティは、1 つのGeometryオブジェクトに設定できます。 これは、コードまたは XAML で実行できます。 通常、その 1 つの GeometryGeometryGroup であり、オブジェクト モデルの目的で複数のジオメトリ定義を 1 つのオブジェクトに合成できるコンテナーとして機能します。 これを行う最も一般的な理由は、PathFigureSegments値BezierSegment など) として定義できる 1 つ以上の曲線と複雑な図形を使用するためです。

この例では、Blend for Visual Studio を使用してベクター図形をいくつか生成し、結果を XAML として保存した結果のPathを示します。 Pathの合計は、ベジエ曲線セグメントと線分で構成されます。 この例はメイン Path.Dataシリアル化形式に存在する要素と数値が表す要素の例をいくつか示すことを目的としています。

このDataは、「M」で示される移動コマンドで始まり、パスの絶対的な開始点を設定します。

最初のセグメントは、(100,200) で始まり (400,175) で終わる 3 次ベジェ曲線で、2 つの制御点 (100,25)(400,350) を使用して描画されます。 このセグメントは、Data属性文字列の「C」コマンドによって示されます。

2 番目のセグメントは、絶対水平線コマンド「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を次に示します。

Screenshot of a simple rendered path.

次の例では、説明した他の手法である PathGeometry を持つ GeometryGroup の使用方法を示します。 この例では、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);

レンダリングされたPathを次に示します。

Screenshot of a complex rendered path.

PathGeometryを使用すると、Path.Data文字列を設定するよりも読みやすい場合があります。 一方、 Path.Data はスケーラブル ベクター グラフィックス (SVG) イメージ パス定義と互換性のある構文を使用するため、SVG からグラフィックスを移植したり、Blend などのツールからの出力として使用したりするのに役立ちます。