WPF on .NET Coreをやってみる（プレビュー版）

# はじめに

この記事は C# Advent Calendar 2018 08日目の記事です

ついに.NET Core上でデスクトップ開発ができるようになりました。
この記事では.NET Core上で動作するWPFを試してみます。
合わせて最新のC#8.0機能と.NET Frameworkのライブラリが動作するかも実験してみます。

なお使用したバージョンはプレビュー版です。
また.NET CoreといってもLinuxやMacでは動きません。

# インストール方法

[VisualStudio 2019 Preview をダウンロード](https://visualstudio.microsoft.com/ja/vs/preview/)してインストールします。
ちなみにVisualStudio2019は他の2017とかと完全に別なので共存してインストール・使用することができます。

- .NET デスクトップ開発
- .NET Core クロスプラットフォームの開発

をチェックしてインストールします。

さらに[.NET Core 3.0 Previewをダウンロード](
https://dotnet.microsoft.com/download/dotnet-core/3.0)してインストールします。


# Hello World

まだVisualStudioから.NET Core WPFを新規作成することはできないので、コマンドから作成します。
まず任意のプロジェクト名のフォルダを作り、そこで以下のコマンドを実行します。

```console
dotnet new wpf
```

そして出来上がった.csprojファイルをVisualStudio2019から開きます。
Xamlのプレビューやプロパティウインドウなどは動きません。

![無題5.png](https://qiita-image-store.s3.amazonaws.com/0/120077/c5ba3951-a80a-dc2c-6b40-940cb198c532.png)


そのまま実行すると、、、

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/120077/ded03b2b-f436-ad41-b50e-c9f53a081e05.png)

無事に表示されます。
ライププロパティエクスプローラなどのUIデバッガーは動きませんが、通常のデバッガーは動きますのでブレークポイントで止めたりすることはできます。

VisualStudioを一旦閉じます。
閉じる際にダイアログで.slnファイルを作成するか聞かれるので、作成します。

# .NET Core APIの使用

ソリューションを再び開きます。
C# 8の文法を使用してみます。
まずデフォルトではビルド設定を変更します。
プロジェクトのプロパティ＞ビルド＞詳細設定＞言語バージョン
をC# 8.0に変更します。

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/120077/3dd03dee-6c42-461f-ecd3-3c512d9a47b5.png)

今回はRangeを使用してみます。
MainWindowを少し変更します。

```xml:MainWindow.xaml
<Window x:Class="WpfNetCoreVSPre.MainWindow"
...
        Title="MainWindow" Height="450" Width="800">
   <StackPanel>
      <TextBlock Text="" x:Name="tbSelected" FontSize="72"/>
      <Button Content="Select Center"  Click="ButtonSelectCenter_Click"/>
      <Button Content="Select Last"  Click="ButtonSelectLast_Click"/>
   </StackPanel>
</Window>
```

```csharp:MainWindow.xaml.cs
public partial class MainWindow : Window
{
    private int[] source = new int[] { 0, 10, 20, 30, 40, 50 };

    public MainWindow()
    {
        InitializeComponent();
    }

    private void ButtonSelectCenter_Click(object sender, RoutedEventArgs e)
    {
        tbSelected.Text = String.Join(' ', source[2..5]);
    }

    private void ButtonSelectLast_Click(object sender, RoutedEventArgs e)
    {
        tbSelected.Text = $"{source[^1]}";
    }
}
```

MainWindowのコードビハインドの`source[2..5]`や`source[^1]`がRange機能です。
ボタンを押したときに元配列の2～4番目、最後から1つ目を取得する機能です。

実行結果です。

![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/120077/9bdf1b53-d754-e47e-709d-7b9e455a5c21.png)

# .NET Frameworkライブラリの使用

次に.NET Coreに正式対応していない、.NET Frameworkのライブラリをつかってみます。
今回は[MaterialDesignInXamlToolkit
](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit)を使用します。

プロジェクトにNugetで以下の2つを追加します。

- MaterialDesignColors
- MaterialDesignThemes

.NET Frameworkにしか対応いていないので警告が出ますが、とりあえず無視します。
MaterialDesignInXamlToolkitのチュートリアルに沿っていくつか変更します。

App.xamlにResourceDictionaryを追加します。
私の好みで色をダークテーマ + プライマリ:BlueGrey + アクセント:Cyanにしました。

```App.xaml
<Application x:Class="WpfNetCoreVSPre.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfNetCoreVSPre"
             StartupUri="MainWindow.xaml">
   <Application.Resources>
      <ResourceDictionary>
         <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Dark.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Bluegrey.xaml" />
            <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Cyan.xaml" />
         </ResourceDictionary.MergedDictionaries>
      </ResourceDictionary>
   </Application.Resources>
</Application>
```

次にViewを少し変更します。コードビハインドは変更しません。
TextBlockをCardで囲い、下のButtonはStyleを変更してContentもPackIconに変更しました。

```MainWindow.xaml
<Window x:Class="WpfNetCoreVSPre.MainWindow"
        ...
        xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
        TextElement.Foreground="{DynamicResource MaterialDesignBody}"
        Background="{DynamicResource MaterialDesignPaper}"
        Title="MainWindow" Height="450" Width="800">
   <StackPanel>
      <materialDesign:Card Margin="5">
         <TextBlock Text="" x:Name="tbSelected" FontSize="72" Margin="5"/>
      </materialDesign:Card>
      <Button Content="Select Center"  Click="ButtonSelectCenter_Click" Margin="5"/>
      <Button Click="ButtonSelectLast_Click" Style="{StaticResource MaterialDesignFloatingActionMiniAccentButton}" Margin="5">
         <materialDesign:PackIcon Kind="PageLast"/>
      </Button>
   </StackPanel>
</Window>
```

実行結果です。問題なく動きます。

![無題4.png](https://qiita-image-store.s3.amazonaws.com/0/120077/62fc4eb4-b12b-03ec-1c10-90403ca3df76.png)

警告文が出た以外は今のところ、.NET Frameworkのときと違いはないですね。

# まとめ

というわけでVisual Studio 2019と.NET Core3.0を使って最新のC#8.0の文法と.NET Frameworkのライブラリの同時使用ができました。
Windowsのデスクトップ開発はWinFormからUWPまでいろいろな選択肢がありますが、このWPF on .NET Coreも新たな選択肢として検討する価値はありそうです。

ソースコード全体を以下の場所に置いてあります。
https://github.com/soi013/WpfNetCoreVSPre

# 環境
Visual Studio 2019 16.0.0 Preview 1.0
.NET Core 3.0 (Beta)
MaterialDesignThemes 2.5.0.1205

# 参考

[Update your Windows desktop app to .NET Core 3.0.100-preview-009754 – App Consult Team](https://blogs.msdn.microsoft.com/appconsult/2018/11/16/update-your-windows-desktop-app-to-net-core-3-0-100-preview-009754/)

[.NET Core 3.0 でのデスクトップ開発 - かずきのBlog@hatena](https://blog.okazuki.jp/entry/2018/12/05/160649)

[Announcing .NET Core 3 Preview 1 and Open Sourcing Windows Desktop Frameworks | .NET Blog](https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-net-core-3-preview-1-and-open-sourcing-windows-desktop-frameworks/?utm_source=vs_developer_news&utm_medium=referral)

[C# 8.0 Ranges | ++C++; // 未確認飛行 C ブログ](https://ufcpp.net/blog/2018/12/cs8ranges/)