[WPF] Grid.Clipで表示領域を制限する(好きな形に切り抜く)

# もくじ

https://tera1707.com/entry/2022/02/06/144447

# やりたいこと

以前、WinFormsで「画像の一部を切り抜いて表示させる」ということをしたときにえらい苦労した記憶だけがある(やり方は覚えてない)が、そういうことがWPFでは簡単にできるというのを人に教えてもらったので、試してみたい。

# やり方

`<Grid.Clip>`と`〇〇Geometry`を使う。

# サンプル(楕円で切り抜き)

赤に塗ったGridを、楕円の形に切り抜いて表示する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/0aa0b399-acf1-3b30-3d0a-c18e63541ef0.png)

```MainWindow.xaml
<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <!-- Grid全体を赤に塗る -->
        <Grid.Clip>
            <GeometryGroup FillRule="EvenOdd">
                <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
            </GeometryGroup>
        </Grid.Clip>

        <!-- Grid全体を赤に塗る -->
        <Grid Background="Red"/>
    </Grid>
</Window>
```



# サンプル(複合図形で切り抜き)

3つの図形(三角形、縦長の楕円、横長の楕円)の複合図形で切り抜き。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/ac295a34-322e-628e-71ac-c900a8530eb8.png)


```MainWindow.xaml
<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <!-- 切り抜く形を指定 -->
        <Grid.Clip>
            <GeometryGroup FillRule="Nonzero">
                <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                <PathGeometry >
                    <PathGeometry.Figures>
                        <PathFigureCollection>
                            <PathFigure IsClosed="True" StartPoint="0,0">
                                <PathFigure.Segments>
                                    <PathSegmentCollection>
                                        <LineSegment Point="0,0" />
                                        <LineSegment Point="100,0" />
                                        <LineSegment Point="50,100" />
                                    </PathSegmentCollection>
                                </PathFigure.Segments>
                            </PathFigure>
                        </PathFigureCollection>
                    </PathGeometry.Figures>
                </PathGeometry>
            </GeometryGroup>
        </Grid.Clip>

        <!-- Grid全体を赤に塗る -->
        <Grid Background="Red"/>
    </Grid>
</Window>
```

上のサンプルでは、`GeometryGroup`の`FillRule`を`NonZero`にしているので、図形が重なった部分全部を使って切り抜く形になる。

これを 

```a.xaml
<GeometryGroup FillRule="EvenOdd">
```

にすると、図形が奇数回重なったところだけ切り抜く(表示する)という形になる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/cf296460-233c-1eff-7b7e-56b78475aaad.png)

# その他

今回、`<GeometryGroup>`を使って複数の図形を重ねるということをしたが、それ以外にも`<CombinedGeometry>`というのを使っても似たことができるらしい。

https://gogowaten.hatenablog.com/entry/15921152

いずれ試したい。

# 参考

`<GeometryGroup>`には、`Geometry`から派生するいろいろなGeometryを、入れれそう。
今回は変な形をサンプルにしたが、基本の`RectangleGeometry`とかは、いろいろなケースで使えそうな気がする。

https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.media.geometry?view=net-5.0

https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/graphics-multimedia/how-to-create-a-shape-by-using-a-pathgeometry?view=netframeworkdesktop-4.8

https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/graphics-multimedia/how-to-control-the-fill-of-a-composite-shape?view=netframeworkdesktop-4.8