WPF Prism episode: 19 ~ MahApps.Metro と Material Design In XAML Toolkit たちは Prism でも余裕で生き抜くようです! ~

前回記事「Livet が Prism に「IDisposable 呼び出し用」としてゲッツされた件【episode: 18 WPF Prism】」

 

前回は Livet の機能別パッケージを導入して Window と UserControl の VM を Dispose する方法を紹介しました。

ここまでの連載では WPF アプリケーションを MVVM パターンで作成する場合の内部的な動作をメインに紹介してきましたが、やはり WPF と言えばスタイリッシュな画面を作成し易いのもウリだと思うので、今回は MahApps.Metro と Material Design In XAML Toolkit をサンプルアプリに組み込む方法を紹介します。

尚、この記事は Visual Studio 2019 Community Edition で .NET Core 3.0 以上 と C# + Prism 7.2 以降 + ReactiveProperty + Livet + MahApps.Metro + Material Design In XAML Toolkit を使用して 、WPF アプリケーションを MVVM パターンで作成するのが目的で、C# での基本的なコーディング知識を持っている人が対象です。

MahApps.Metro と Material Design In XAML Toolkit

MahApps.MetroMaterial Design In XAML Toolkit は WPF アプリケーションの UI ライブラリとしてはメジャーだと思いますし、日本語での記事を見かけることも多いので新鮮味は少ないと思いますが、モダンでマテリアルデザイン風の画面を作成したい場合は便利なのでこの連載でも取り上げることにします。

MahApps.Metro

MahApps.Metro は GitHub で公開されている OSS ライブラリで fig. 1 のように Window のタイトルバーにボタン等を追加したり、Visual Studio のような枠が光る Window も簡単に作成できます。

fig.1 MahApps.MetroWindow サンプル

MahApps.Metro はカスタマイズ可能な Window に加えて統一されたデザインのコントロールも多数含まれている UI ライブラリです。



Material Design In XAML Toolkit

もう一方の Material Design In XAML Toolkit も MahApps.Metro 同じく GitHub で公開されている OSS ライブラリで、Google が提唱している Material Design を XAML(WPF アプリケーション)で表現するためのコントロールライブラリです。

Material Design In XAML Toolkit を導入すると fig. 2 のようなボタンをはじめとするマテリアルデザインなコントロールを使うことができるようになります。

fig.2 Material Design In XAML Toolkit サンプル

fig. 2 は Material Design In XAML Toolkit のデモアプリの一画面で、アプリケーションへ設定可能なボタンが一覧で確認できます。
Material Design In XAML Toolkit はボタンだけでなく標準の WPF コントロールをマテリアルデザイン風に変えるデザインテンプレートが多数含まれている UI ライブラリです。

MahApps.Metro と Material Design In XAML Toolkit のインストール

episode: 18 で作成したサンプルアプリは fig. 3 のような平凡でシンプルな WPF 標準の画面なので、このサンプルアプリを MahApps.Metro と Material Design In XAML Toolkit でマテリアルデザイン風の画面にする手順を紹介します。

fig.3 WPF 標準のサンプルアプリ

MahApps.Metro と Material Design In XAML Toolkit は連携して使用できるようになっていて Nuget からインストールできます。まずは【ソリューションの Nuget パッケージの管理】画面で 【materialdesign】を検索して表示される【MaterialDesignThemes.MahApps】を XAML が含まれるプロジェクトへインストールします。

fig.4 MaterialDesignThemes.MahApps のインストール

但し、この連携パッケージに含まれる MahApps.Metro と Material Design In XAML Toolkit はどちらも単独のパッケージより少し古いバージョンなのでインストール後は fig. 5 のように多くの警告が表示されます。

fig.5 インストール後の警告

この連携パッケージではなく個々にパッケージをインストールしても問題ないと思いますが、一応手順通り紹介します。

MahApps.Metro の更新

まず MahApps.Metro から先に更新します。(どちらから更新しても構いません)
前項と同じく【ソリューションの Nuget パッケージの管理】画面で 【mahapps】を検索して表示される【MahApps.Metro】を前項で選択したのと同じプロジェクトへインストールして最新版に更新します。

fig.6 MahApps.Metro の更新(インストール)

MahApps.Metro を更新しても警告は消えないはずなので、続いて Material Design In XAML Toolkit も更新します。

Material Design In XAML Toolkit の更新

引き続き、【ソリューションの Nuget パッケージの管理】画面で 【materialdesign】を検索して表示される【MaterialDesignThemes】と【MaterialDesignColors】を前項と同じプロジェクトへインストールして最新版に更新します。

fig.7 Material Design In XAML Toolkit の更新(インストール)

両方を更新しても警告が消えないのは episode: 18 でも紹介したように両方とも .NET Core 3.0 対応版がリリースされていない(2019/10/20 現在)からです。

.NET Core 3.0 非ネイティブの警告を抑制するには fig. 8 のように【プロジェクトのプロパティ】-【ビルド】-【警告の非表示】へ【NU1701】を追加します。

fig.8 警告の抑制

fig. 8 の設定を保存するとエラー一覧から警告が消え、ソリューションエクスプローラーの緑波線も消えると思います。

MahApps.Metro と Material Design In XAML Toolkit をアプリで使用する設定

MahApps.Metro と Material Design In XAML Toolkit を連携するための設定は Material Design In XAML Toolkit の Wiki で紹介されている通りですが、ここでも一応紹介しておきます。

まずは App.xaml へ src. 1 のハイライト部を貼り付けます。

src. 1 に追加した内容については Material Design In XAML Toolkit の Wiki を翻訳すれば大体の意味は分かると思いますが、変更が必要な所は特に無いので src. 1 から貼り付けたままで問題ありません。

MahApps.Metro と Material Design In XAML Toolkit を連携してアプリ上で使用するための設定は以上ですが、Window を MahApps.Metro の MetroWindow にするには Window の継承元を MetroWindow に変更する必要があります。



Window の継承元を変更

まず XAML 側の継承元を src. 2 のように MetroWindow に変更します。

XAML の変更に合わせて Window のコードビハインドも src. 3 のように継承元を MetroWindow に変更して完了です。

.NET Framework で作成する場合はここまでの設定で MetroWindow が表示できますが、.NET Core 3.0 で作成した場合は実行すると fig. 9 のような FileNotFoundException が Throw されます。

fig.9 FileNotFoundException

MahApps.Metro か Material Design In XAML Toolkit のどちらかが .NET Core に標準では含まれていないクラスを呼び出していることが原因のようなので、fig. 10 のように【ソリューションの Nuget パッケージの管理】画面で 【system.management】を検索して表示される【System.Management】をスタートアッププロジェクトへインストールします。

fig.10 System.Management のインストール

管理人の環境では System.Management インストール後に『’Microsoft.CodeAnalysis.Xaml.Diagnostics.Analyzers.XamlDocumentDiagnosticAnalyzer’ が型 ‘System.NullReferenceException’ の例外をメッセージ ‘オブジェクト参照がオブジェクト インスタンスに設定されていません。’ 付きでスローしました。』と言う警告が表示され、リビルドしても消えませんでしたが以降の設定を進めていくといつの間にか消えていたので、表示された場合はそのままにして先へ進んでも大丈夫だと思います。(どんな環境でも表示されるかは不明です)

ここまでで実行すると MainWindow は fig. 11 のような MetroWindow のスタイルで表示されるようになります。

fig.11 Metro Window

このように MahApps.Metro と Material Design In XAML Toolkit は Prism のテンプレートから作成したプロジェクトでも通常の WPF アプリと同じ手順で適用することができます。

Prism の Shell プロジェクトには標準の WPF アプリと同じく App.xaml へ src. 1 の設定を追加する必要がありますが、Module プロジェクトは MahApps.Metro と Material Design In XAML Toolkit をインストールするだけで、fig. 11 のように TreeViewItem の Hover や選択時に効果が付加されるようになります。

次章以降では主な設定項目を簡単に紹介していきます。

MetroWindow の設定項目

MetroWindow は設定項目が多く全て説明できないので、【MahApps.Metroを使ってみた – SourceChord】やオブジェクトブラウザ等を参考にいじってみてください。

ここでは MetroWindow の 4 つのプロパティを紹介するので、まずは MainWindow の XAML へ src. 4 のハイライト部分を追加します。

追加したプロパティは以下の通りです。

プロパティ設定内容
TitleCharacterCasingNormal を設定するとタイトルバーの文字列が設定通り大文字・小文字が混在して表示されます
Upper を設定(デフォルトは Upper)した場合は fig. 11 のように全て大文字で表示され、Lower を設定すると全て小文字で表示されます。
SaveWindowPositionTrue を設定すると Window の位置とサイズを保存するようになり次回表示する際に復元されます。
GlowBrushWindow のボーダー(枠線)を Visual Studio のような光る枠線で描画します。
描画色は App.xaml に追加したブラシを指定しています。
BorderThicknessWindow の枠線太さをピクセル単位で設定します。

上記 4 つを設定して実行すると MainWindow の表示が fig. 12 のようになります。

fig.12 プロパティ設定後の MainWindow

fig. 12 では光る枠線は分かりにくいかもしれませんが、タイトルバーが大文字・小文字の混在に変わったのが確認できると思います。

又、SaveWindowPosition を True に設定すると Window の終了時位置とサイズを保存してくれるようになるので、サイズや位置を変更して終了後、再実行して位置やサイズが復元されるのを確認してみてください。

Window の位置とサイズは『ユーザフォルダ\AppData\Local\{アプリ名}\{アプリ名テンポラリフォルダ}\{アプリバージョン}』配下の【user.config】へ保存されるので、ファイル自体を削除すると位置・サイズ情報がリセットされます。
※ このサンプルアプリの場合アプリ名に【PrismNetCoreApp】が使用されます(一般的な .NET アプリと同じ)

この他にも MetroWindow にはタイトルバーへボタン等を追加することもできますが、管理人には使用用途が思い付かないので、設定したい場合は他のサイトを参考にしてください。

引き続き Material Design In XAML Toolkit の設定も簡単に紹介します。

Material Design In XAML Toolkit の設定

基本的に標準コントロールは Material Design In XAML Toolkit をインストールするだけでマテリアルデザイン風に変わるので別途設定が必要な場面はあまり多くないはずですが、自分好みの見た目に調整したい場合は XAML でプロパティを設定する必要があり、設定内容の確認にはデモアプリを実行するのが 1 番手っ取り早いので、GitHub の Material Design In XAML Toolkit Releases ページ 等からダウンロードしておきます。

最新版のリリースノートへ【DemoApp.zip】へのリンクがあるはずなので、ダウンロードして展開後 exe を実行すると fig. 13 のような画面が起動します。

fig.13 Material Design In XAML Toolkit デモアプリ

Material Design In XAML Toolkit のデモアプリは非常に便利で、使用できるコントロールを種類別に一覧で確認したり、fig. 14 のように XAML へ設定する内容をデモアプリから直接コピーすることもできます

fig.13 Material Design In XAML Toolkit デモアプリの操作

XAML へ設定する内容はデモアプリだけでも十分確認できますが、Material Design In XAML Toolkit の GitHub ではデモアプリのソースコードも公開されていて、アプリの構成等が知りたい場合等は参考になるのでダウンロードかクローンしておいても良いと思います。
※ MVVM でのサンプルは多くなく大半はコードビハインドに書かれています

Material Design In XAML Toolkit も全ては紹介できないので、今回サンプルアプリに組み込んだ Color Zone コントロールだけを簡単に紹介します。



Color Zone を追加する

Material Design In XAML Toolkit に含まれる Color Zone はアプリのヘッダに使われることも多いコントロールで、これを配置するだけで fig. 14 のように Material Design っぽい見た目になると思います。

fig.14 Color Zone を追加したサンプルアプリ

Color Zone は Prism の Shell、Module どちらに配置しても構いませんが、ここでは Shell である MainWindow へ配置するので、MainWindow の XAML へ src. 5 のようにハイライト部分を追加します。

ColorZone は他の StackPanel とは若干挙動が異なるので注意が必要です。

最も違うのは配置直後の挙動で、通常の WPF コントロールは配置先のコンテナ一杯にサイズが設定されますが、ColorZone は Width・Height が両方とも 0 で配置されます。

そのため、ColorZone 内部へのコントロール追加は必須で、src. 5 では TextBlock を追加してアプリのタイトルを設定しています。
ColorZone 内部へコントロールを追加しても ColorZone は追加したコントロールと同じサイズに描画されるだけなので、Padding の値を変更して見た目を調整する必要があります。
このような挙動の違いは設定をいじって慣れるしかないと思うのでいじりまくってみてください。

ここで使用している ColorZone は単なる飾りの役目しか果たしていませんが、通常は Material Design In XAML Toolkit のデモアプリのように、ColorZone の両サイドへボタン等を配置してドロワーやメニューを表示する用途で使用することが多いと思いますが、機会があれば紹介したいと思います。

又、ColorZone 内部に配置した TextBlock へ設定している『Style=”{StaticResource MaterialDesignHeadlineTextBlock}”』は、Material Design In XAML Toolkit デモアプリの【Typography View】で fig. 15 のように設定をコピーして TextBlock の Style へ設定すると使用できます。

fig.15 Material Design In XAML Toolkit デモアプリ Typography

デモアプリの Typography View で確認できる Style は TextBlock であればどこにでも設定可能なので、文字列の見た目を統一する時に利用できます。

XAML の Style タグへ継承元を指定

TreeViewItem を選択したり展開したりするには extra: 1extra: 2 で紹介した通り、src. 6 のように追加した Style タグへバインドしたいプロパティを追加します。

しかし、src. 6 のように XAML へ Style タグを追加すると XAML では Style を上書き(override)するという意味になるらしく、fig. 11 で紹介したマウスホバー時や選択時の効果は消え去り、fig. 16 のように通常の TreeView に戻ってしまいます。

fig. 16 Material Design In Xaml Toolkit の効果が消えた TreeView

解決方法を探そうにも検索キーワードすら思い付かない状態で悩んでいましたが、『material design in xaml toolkit style override』と言うキーワードで検索するとドンピシャの情報が stackoverflow で見つかりました。

stackoverflow に書いてある通り src. 7 のように Style の BasedOn プロパティへ継承元を指定すると Material Design In XAML Toolkit の効果が復活します。

src. 7  のハイライト部分を追加して実行すると fig. 17 のように効果が戻ってきます。

fig.17 BasedOn に Material Design In XAML Toolkit のリソースを指定した TreeView

BasedOn については『[WPF/xaml]BasedOnを使って元のstyleを受け継ぐ – Qiita』等を見てください。

Material Design In XAML Toolkit を使用していて Style タグを追加した場合は BasedOn の指定が必須だと覚えておけば良いと思います。

Material Design In XAML Toolkit の色設定

Material Design In XAML Toolkit の色設定は App.xaml の 16 ~ 20 行目に当たる src. 8 の部分です。

Window のベースカラーとなる背景色は【Light】と【Dark】の 2 種類が選択でき、src. 6 の 2 行目(App.xaml の 17 行目)で設定します。加えて描画色は【Primary】と【Accent】の 2 種類が指定でき、それぞれ 4 行目と 5 行目(App.xaml の 19 ~ 20 行目)で設定します。

Material Design In XAML Toolkit の定義済み色と代表的な組み合わせは fig. 18 の【デモアプリ – Pallette View】を開くと一覧で確認できます。

fig.18 Material Design In XAML Toolkit デモアプリの Pallette

fig. 18 の Pallette View から好きな 2 色を選択して App.xaml の 19、20 行目へ設定すると反映されます。

Primary と Accent の区分けは目安のようなものなので、Accent となっていても Primary へ設定することができる(逆も同じ)ので好きな組み合わせをデモアプリで試してみると良いでしょう。
又、Primary カラーの濃度は Light、Mid、Dark の 3 種類が用意されていて、カラーを指定する際に指定できるので色々試してみると良いと思います。

このエントリでの紹介はここまでにしますが、Nine Works #MaterialDesignToolkit のようにコントロールごとに詳しく紹介しているブログ等もあるので調べてみてください。
この連載でも必要があれば都度紹介していく予定です。

又、いつものように今回紹介したソースコードは GitHub リポジトリ へ上げています。

 

 

次回記事「Prism ダイアログに MahApps.Metro が舞い降りた!【episode: 20 WPF Prism】」

 

 

おすすめ

8件のフィードバック

  1. 沖田玲朗 より:

    匿名さん>
    これ以上返信ができないので新規スレッドで返信します。

    確かに、認識されないコントロールがある場合は App.xaml に該当するコントロールの ResourceDictionary を追加すれば認識されるようになりますね!

    ただ… やはり MetroDataGridCell について一応管理人も調べてみましたが、納得できる情報は見つかりませんでした…
    Stack Overflow 等でも普通に『MetroDataGridCell』と書かれているので、MahApps.Metro の Style を BasedOn する際は『MahApps.Styles.』を『Metro』に置き換える事が、私たちが知らないだけで公然の事実なのかもしれません。

    このブログでは Material Design In XAML Toolkit のコントロールをメインに取り扱うつもりですが、部分的に MahApps.Metro の Style を適用したいような場合には使えるかもしれないので試してみます。

    現状ではどこで『MahApps.Styles.』を『Metro』に置き換えているのか分かりませんが、分かれば又、記事にしたいと思います。
    お役に立てずすいませんでした。

  2. 匿名 より:

    いつも参考にさせていただき、とても助かっています。
    ありがとうございます。

    私は業務でMahApps.Metro、Prism7.2を使ってアプリケーションを作成しています。

    アプリケーションではDataGridを使用しており、数値を表示するColumnにて特定の値(たとえば負の値)の場合に前景色を赤にするという要件があります。
    下記のようにXAMLに記述すれば、特定の値の場合に文字の色を変えることができたのですが、
    独自のStyleを設定することでせっかくのMetroのオシャレな外観が崩れてしまいました。
    (該当のColumnだけMetroのStyleが反映されず、ハイライト時の背景色が変わったり、GridLineが表示されたりします)

    XAMLの仕組みをよく理解できていないことに起因しているとは思うのですが、
    個別のStyleを設定しつつ、それ以外のStyleは上位(?)のものを引き継ぐということは可能なのでしょうか?

    何かアドバイスをいただけたらと思い、質問させていただきました。
    よろしくお願いいたします。

    • 匿名 より:

      XAMLのコードをコピペしたのですが、表示されないのでしょうか。。

      DataGridTextColumn.CellStyle
      -Style TagetType=”{x:Type DataGridCell}”
      –Setter Property=”Foreground” Value=”{Binding Color}”

      と書いています。

    • 匿名 より:

      本エントリ内に記述がありましたね。申し訳ありません。
      BasedOnで継承元を指定することを試してみます。

    • 沖田玲朗 より:

      こちらこそ読んで頂いてありがとうございます。
      昼間は仕事で返信できないので、遅くなってすいませんでした。

      自己解決されたのでしょうか?
      管理人は DataGrid を使ったことが無いのでお役に立てなかったかもしれませんが、Style タグを追加して MahApps.Metro のスタイルがクリアされるのはやはり BasedOn で継承元を指定するくらいしか思いつかなかったと思います。

      • 匿名 より:

        遅くなったとかとんでもないです。

        何とか解決できました。
        おっしゃる通り、BasedOnで継承元を指定することで問題は解決したのですが、
        StaticResourceの後に記述する名称(?)がピンと来ないといいますか。。

        DataGridCellのStyleを変更する際に継承元を指定するには
        BasedOn=”{StaticResource MetroDataGridCell}”
        と書けば期待する動作になることはなったのですが、
        デザイナで「リソース “MetroDataGridCell”を解決できません」という警告(エラー?)メッセージが表示されます。
        (波線のアンダーラインが入っています)

        githubにあるソース(https://github.com/MahApps/MahApps.Metro/blob/develop/src/MahApps.Metro/Styles/Controls.DataGrid.xaml)を確認しても、”MetroDataGridCell”という名称は見つからないので上記のメッセージが表示されているのだとは思いますが、
        それならば何故思った通りの動作になるのか不思議に思っています。
        本エントリでお書きになっているMaterialDesignTreeViewItemの場合はソースを見たところキーとして登録されていましたが、
        MahApps.Metroの場合はどこかでエイリアスを定義しているのでしょうか。

        • 沖田玲朗 より:

          とりあえず解決できたようで良かったと思いますが…

          > デザイナで「リソース “MetroDataGridCell”を解決できません」という警告(エラー?)メッセージが表示されます。
          MahApps.Metro のリポジトリを検索しましたが確かに “MetroDataGridCell” と言う記述は存在しないようですね。

          元コメントにも書いた通り管理人は DataGrid を使ったことがありませんし、今から試してもコメント頂いている状態まで辿り着ける自身が無いので想像だけでお答えします。

          結論から言うと BasedOn には型も指定できるので、

          BasedOn=”{StaticResource {x:Type DataGridCell}}”

          だとどうでしょうか?

          一応、理由的なことを簡単に書くと、MahApps.Metro や Material Design In XAML Toolkit 等はインストールするだけで WPF 標準コントロールの ControlTemplate が書き換わります。
          そのため、BasedOn に継承元になる型(ここでは DataGridCell)を指定すれば書き換わった ControlTemplate が読み込まれるはずです。

          つまり、このエントリで紹介している MaterialDesignTreeViewItem のようにリソースが定義されている場合はリソースを指定する必要があるが、定義されていない場合は WPF 標準コントロールの型を指定すれば対象ライブラリの ControlTemplate が読み込まれるはずです。

          存在しない MetroDataGridCell を指定したのに何故思った通りの動作になるのかは正直分かりませんが、あくまでも想像で書くと、XAML は記述内容を解釈する際に例外を極力回避するので、存在しない型でもとりあえず例外にはせず、元々プロパティとして定義されている型を読み込んでいるからじゃないかと予想しています。

          そのため現状は元々定義されている型を読み込んでみたら、たまたま MahApps.Metro の ControlTemplate が設定されていた的な状態じゃないかと想像しています。

          試していないので心苦しいですが、BasedOn に型を指定するのは特殊なことではないので一度試してみてください。

          • 匿名 より:

            問題となっていた警告メッセージが表示されなくなりました。
            これが直接の原因なのかわかりませんが、App.xamlのMergedDictionariesに
            ResourceDictionary Source=”pack://application:,,,/MahApps.Metro;component/Styles/Controls.DataGrid.xaml”の記述を追加しました。

            また、他のコントロールでもBasedOnを使って継承する場合であってもソースコードに書かれているキーを指定できなくなっています。
            (ListBoxの場合、MahApps.Styles.ListBoxというキーのStyleですが、BasedOnで指定する場合はMetroListBoxと書かなくてはいけません。)

            内部的に”MahApps.Styles.”を”Metro”で置き換える(読み替える)ような構造になっているのかと推測したのですが、今のところそれらしい記述は見つかっていません。。

            ちなみに、BasedOnでx:Typeによって型を指定したところ、MetroのStyleではなくデフォルトの見た目になりました。つまり、書き換わる前の(?)ControlTemplateが読み込まれていると考えられます。

            謎が深まってしまいましたが、一旦解決したということで頭の片隅に残す程度にしておきます。
            お手数をおかけして申し訳ありませんでした。
            また、丁寧な回答ありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください