shuhelohelo’s blog

Xamarin.Forms多めです.

すでにあるWPFアプリをマテリアルデザインにする[引越記事]

<2018年一人アドベントカレンダー9日目>

はじめに

何番煎じかという内容です。 こちらを参考に自分で手を動かしてみたことの備忘録です。

さて、いつもと違うデザインでアプリを作ってみると、とても新鮮に感じられてテンションが上ります。

NugetでMaterialDesignThemeMahApps.Metroというパッケージをインストールすることで、簡単に見た目をマテリアルデザインにすることができます。

環境

MaterialDesignTheme

まずはWPFプロジェクトを新規作成するか、すでに作成済みWPFプロジェクトをVisual Studioで開きます。

インストール

次に、NugetでMaterialDesignThemeを検索してインストールします。 image.png

設定

App.xamlResourceDictionaryに以下のようにコードを入れます。

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

とりあえずこれでマテリアルデザインが適用されて、

before

image.png image.png

after

image.png

image.png

となります。

おお、、、?という感じになったのではないでしょうか。 ボタンやプログレスバーの色、形状がマテリアルデザインぽくなってはいますが、UIのデザイン変更にともなってボタンのラベルが収まらなかったり、ラジオボタンが他のコントロールに隠れて切れたりしています。 これは要素ごとにスタイルを設定するなどして調整します。これはいつもどおりです。

それと、一番気になるのがタイトルバーのミスマッチです。タイトルバーだけノーマルなので浮きまくりです。

これを解決するのがMahApps.Metroです。 MahApps.Metro自体は名前のとおりWPFアプリのWindowのデザインをWindowsのモダンUI風にしてくれるものですが、マテリアルデザインとの相性が良いのです。

MahApps.Metro

インストール

NugetでMahApps.Metroを検索してインストールします。 image.png

設定

xamlファイルのWindow要素を以下のように変更します。 Window要素の代わりにMahAppsのMetroWindow要素を使います。

<Window x:Class="MyApplication.MainWindow"
               省略
<mahApps:MetroWindow x:Class="MyApplication.MainWindow"
               省略
        xmlns:mahApps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"

XML側のWindow要素をMetroWindow要素に変更したので、それに合わせてコードビハインド(xaml.cs)も以下のようにWindowからMetroWindowを継承するように変更します。

    public partial class MainWindow : Window
    {
          省略
    }
    public partial class MainWindow : MahApps.Metro.Controls.MetroWindow
    {
          省略
    }

ここはWindowごとに設定する必要があります。

次に、App.xamlMetroDesignThemeと同じようにResourceDictionaryに以下のように追記します。 MahApps.Metroのための追記を行った後はいかのようになります。

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--MaterialDesignThemes-->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />

                <!--MahApps.Metro-->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>

さて、これでどうでしょうか。 一度実行してみましょう。

image.png

タイトルバーとステータスバーのデザインが変わり、色はともかくとしてぐっとマテリアルデザインぽくなりました。 さて、App.xamlにさらに追記して以下のようにします。

    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--MaterialDesignThemes-->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />

                <!--MahApps.Metro-->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <!--MahApps.Metro-->
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentColorBrush" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="AccentColorBrush2" Color="{DynamicResource Primary400}"/>
            <SolidColorBrush x:Key="AccentColorBrush3" Color="{DynamicResource Primary300}"/>
            <SolidColorBrush x:Key="AccentColorBrush4" Color="{DynamicResource Primary200}"/>
            <SolidColorBrush x:Key="WindowTitleColorBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentSelectedColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <LinearGradientBrush x:Key="ProgressBrush" EndPoint="0.001,0.5" StartPoint="1.002,0.5">
                <GradientStop Color="{DynamicResource Primary700}" Offset="0"/>
                <GradientStop Color="{DynamicResource Primary300}" Offset="1"/>
            </LinearGradientBrush>
            <SolidColorBrush x:Key="CheckmarkFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="RightArrowFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="IdealForegroundColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <SolidColorBrush x:Key="IdealForegroundDisabledBrush" Color="{DynamicResource Primary500}" Opacity="0.4"/>

        </ResourceDictionary>
    </Application.Resources>

ここまでやると、こんな感じになりタイトルバーとステータスバーのデザインはマテリアルデザインっぽくなりました。

image.png

image.png

でも別の問題がでています。 ボタンのデザインがマテリアルデザインじゃなくなっています。 これはスタイルの適用順序のせいです。

上で示したApp.xamlの例ではMaterialDesignThemesMahApps.Metroの順に書いていました。このため、MahApps.Metroのスタイルが適用されてボタンなどのデザインがマテリアルデザインではなくなってしまっていました。 ということ順番を入れ替えて以下のようにします。

            <ResourceDictionary.MergedDictionaries>
                <!--MahApps.Metro-->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />

                <!--MaterialDesignThemes-->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
            </ResourceDictionary.MergedDictionaries>

そうすると・・・

image.png

image.png

あとはボタンのラベルや、UIの高さなど細々したところを調整します。

image.png

image.png

おわりに

いつも見慣れたWPFアプリもこうして見た目を変えるだけで印象がかなり違ってきますし、作るときのモチベーションも上がりますよね。