.NET5.0/C#9.0でオートシェイプ風図形描画ライブラリを作ろう！(Chapter0) 

.NET5.0も正式リリースされ、C#言語バージョンも9.0となりました。
とはいえ、私自身C#の知識が7.0くらいの知識からアップデートされていなかったりします。

そこで今回はC#8、9辺りの新しい機能を意識しつつ、.NET5.0のアプリケーションを一から作ってみようと思います。

## 作るもの
さて、何を作るかですが
「ほとんどの人がどのようなものか知っている（仕様の説明が要らない）」
「実装の結果が視覚的にわかりやすい」
との理由からWord、Excel等についているオートシェイプ機能のような図形描画のライブラリを作ることとしました。

- オートシェイプ機能のような図形描画のライブラリを.NET5.0クラスライブラリとして作ります。
- このライブラリを利用したサンプルアプリケーションをWPFで作成します。
- サンプルでは2DグラフィックスエンジンのSkiaSharpを使います
- (それ以外はノープランです)

※ 行き当たりばったりで設計しながら作る過程を連載記事として公開してゆく予定ですので、「それあまり良くない設計ですよ」とか「もっといい方法ありますよ」などフィードバックをいただけますと大変うれしいです。

### ソースコード
本記事のソースコードはGitHub上に置いておきます。

https://github.com/pierre3/CoreShape

（「blog/cahpter0-2」のように章ごとにブランチを切っていく予定です）

## 記事一覧（予定）

- __Chapter0 ソリューションの作成__
- [Chapter1 画面上に図形を描画するための仕組みを作ろう](https://qiita.com/pierusan2010/items/fb8aceda5416213440b1)
- [Chapter2 ドラッグ操作で図形を動かしてみよう](https://qiita.com/pierusan2010/items/5862ac88303ddbdf15b4)
- [Chapter3-1 ドラッグ操作で図形のサイズを変更してみよう(その１)](https://qiita.com/pierusan2010/items/3a1e49ee0edb71b36368)
- [Chapter3-2 ドラッグ操作で図形のサイズを変更してみよう(その２)](https://qiita.com/pierusan2010/items/93f0ec5994581dbdbaa7)
- [Chapter4 図形を配置するためのクラスShapePenを作ろう!](https://qiita.com/pierusan2010/items/60f3e63bee5966d7ec20)
- [Chapter5 WPFアプリをリファクタリングしょう](https://qiita.com/pierusan2010/items/531199fbff10477f3064)

それでは、まずは開発の準備から始めましょう！

## Chapter0 ソリューションの作成
Visual Studio2019 の最新バージョン(12/13現在はVersion 16.8.3)を使用して開発します。

### プロジェクトの構成
以下のような構成でプロジェクトを作成します。

- `CoreShape`: 今回作成するメインのプロジェクト （.NET5.0 クラスライブラリ)
- `CoreShape.Extensions.SkiaSharp`: SkiaSharp向けのCoreShape拡張。インターフェースの実装や拡張メソッドなどを定義（.NET5.0クラスライブラリ）
- `SkiaSharp`: 2Dグラフィックスエンジン（NuGetライブラリ参照）
- `SampleWPF`: サンプルアプリ（WPF(.NET5.0)App）

CoreShapeライブラリはどのプラットフォーム、ライブラリにも依存しないポータブルな状態を保つようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/524fad18-e54f-57d0-cb6b-62b8fe2e403b.png)


### プロジェクトの作成

#### .NET5.0プロジェクトテンプレートの表示
.NET5.0 対応のプロジェクトテンプレートを利用するには今のところVisual Studioのオプション設定を変更する必要があります。

- メニューバーで「ツール」-「オプション」を選択
- オプションダイアログの左側で「環境」-「プレビュー機能」を選択
- 「「新しいプロジェクト」ダイアログに全ての.NET Coreテンプレートを表示する」にチェックを付ける

<img alt="image01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/f914067e-79d2-b25a-23a4-6a836e83ec0b.png" width="600" />

#### .NET5.0クラスライブラリの作成
下記の手順で「CoreShape」及び「CoreShape.Extensions.SkiaSharp」のプロジェクトを作成します。

- メニューバーで「ファイル」-「新規作成」-「プロジェクト」を選択 
- 「新しいプロジェクトの作成」ダイアログでテンプレート「Class library」を選択して「次へ」
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/07a43b40-3537-6daf-1226-3ea8702e48b5.png" width=600 alt="image02" />

- プロジェクト名「CoareShape」を入力して「次へ」
- 「追加情報」でターゲットフレームワークで「.NET5.0」を選択して「作成」
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/0844b596-107d-1796-0b15-dafc9e58bd78.png" width=600 alt="img03" />

- メニュー「ファイル」-「追加」-「新しいプロジェクト」から「CoreShape.Extensions.SkiaSharp」プロジェクトも同様に作成します。
 

#### WPF(.NET5.0)Appの作成
続けてWPFアプリケーション（SampleWpf）のプロジェクトを作成します。

- メニューバーで「ファイル」-「追加」-「新しいプロジェクト」を選択
- 「新しいプロジェクトの追加」ダイアログでテンプレート「WPF Application」を選択して「次へ」
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/94c1fc9e-928c-e455-463b-85e59aa946f9.png" width=600 alt="img04" />

- プロジェクト名を入力して「次へ」
- 「追加情報」でターゲットフレームワークで「.NET5.0」を選択して「作成」
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28805/a6ffc507-1b65-c4d9-3c16-777bc4de831e.png" width=600 alt="img04" />

#### SkiaSharpのNuGetパッケージを追加

「ツール」-「NuGetパッケージマネージャ」-「ソリューションのNuGetパッケージの管理」を開き、「SkiaSharp」のパッケージを検索し、プロジェクトに追加します。

- 「SampleWPF」プロジェクトに「SkiaSharp.Views.WPF」の最新安定バージョンを追加します
- 「CoreShape.Extensions.SkiaSharp」プロジェクトに「SkisSharp」の最新安定バージョンを追加します。

#### プロジェクトの参照
下記の通りにプロジェクト間の参照設定を行います。

- SampleWPF  
  → CoreShape、CoreShape.Extensions.SkiaSharp を参照
- CoreShape.Extensions.SkiaSharp  
  → CoreShape を参照

#### NULL許容コンテキストを有効にする
作成されたcsprojファイルに `<Nullable>enable</Nullable>` を追加します。
こうすることで参照型もNULL非許容が前提となり、NULL以外の値に初期化しないと警告が出るようになります。（作成した全てのプロジェクトでこの設定を行います）

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
```
[Null許容参照型 - C#リファレンス](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/builtin-types/nullable-reference-types)

#### 描画面の設定

SampleWPFでMainWindow.xamlを開き、SkiaSharpで図形を描画するためのコントロール`SKElement`を追加します。

```xml
<Window x:Class="SampleWPF.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:skiaSharp="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
        xmlns:local="clr-namespace:SampleWPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <skiaSharp:SKElement x:Name="skElement" 
                             PaintSurface="sKElement_PaintSurface" />
    </Grid>
</Window>
```
そしてコードビハインド（MainWindow.xaml.cs）には描画面を更新する際のイベント `PaintSurface`のイベントハンドラを追加しておきます。

```cs
private void sKElement_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
    //ここに図形描画の処理を記述します。
}
```

これで実装前の準備は完了です。

## 次回

次回は

- [Chapter1 画面上に図形を描画するための仕組みを作ろう](https://qiita.com/pierusan2010/items/fb8aceda5416213440b1)

です。