WPFでデスクトップアプリを構築するメリットの1つに、見栄えの良い(モダンな)画面デザインが実現しやすいという点があります。
とはいうものの、マイクロソフトが提供する標準機能だけでは限界があり、XAMLに関する高度な知識が不可欠です。
でも、安心して下さい! Material Design In Xaml Toolkitを導入すれば、WPFでも簡単にWeb風の魅力的な画面を構築することができます。
本記事では、Material Design In Xaml Toolkitのインストール方法と使い方について、豊富なキャプチャ画像を使って解説していきます。
WPFでモダンなデザインを手軽に実現する方法をお探しの方は、是非参考にして下さい。
Material Design In Xaml Toolkit で実現できる画面例
Material Design Xaml In Toolkitを使うと、WPFで用意されている標準コントロール(TextBox、ComboBox、DataGrid、TabControlなど)のデザインを見栄え良くしてくれます。また、XAMLに専用タグを記述することで、今まで実現困難だったデザインや操作性が簡単に実現できます。
Material DesignとMaterial Design In Xaml Toolkit
Material Designは、Googleが提唱した新しいデザインの一種です。2014年に導入され、明確なガイドラインが定められています。
Material Design Xaml In Toolkit は、Material DesignのルールをWPFで実現するためのライブラリ集であり、Material Designに関する詳しい知識がなくても、そのルールに沿った画面が実現できます。
Material Designの特徴とメリット・デメリット
Material Designの目的は「見やすく、直感的に操作できるWebページやサービス」を作成することであり、次の特徴があります。
特徴 | 説明 |
---|---|
現実世界の物理法則を取り入れる | 現実世界の物理的なルールを画面に反映させ、直感的な操作を実現すると 共に、影や質量感などを考慮して立体感を演出 |
紙とインクの要素で組み立てる | 画面を印刷物のようにデザインし、色や画像の配置、余白の使い方などを工夫 |
少ない色でシンプルな配色 | 最大4色の有彩色を選び、メインカラー、サブカラー、アクセントカラー として使用 |
立体感を出すために影を活用 | 陰影をつけてUIパーツの役割を強調し、視覚的な情報を提供 |
アニメーションで連続性を演出 | ユーザーの操作と連動したアニメーションを使い、スムーズな遷移を実現 |
もちろん、Material Designを使う場合においてメリットとデメリットが存在します。
メリット | デメリット |
---|---|
現実世界の物理法則に従うため直感的な操作が可能 厳密は配色ルールにより画面が見やすい | 覚えることが多く、慣れるまで時間がかかる |
Material Design Xaml In Toolkit は、「覚えることが多く、慣れるまで時間がかかる」というデメリットを解消するための手段であると言えます。
個人的にはもう1つ大きな利点を感じています。それはボタン等に付けるアイコンを別途入手する必要が無いという点です。Material Design の標準アイコンが7000種類以上用意されており、どれでも自由に使うことができるようになっています。
どのようなアイコンが用意されているかは、Material Design Icons のページで公開されています。
Material Design Xaml Toolkit のインストール手順概要
Material Design Xaml Toolkit は、Material DesignThemesと ShowMeTheXAML.MSBuildの2つのモジュールで構成されています。また、Xamlファイルにコードの追加が必要になります。
具体的には次の手順が必要です。とりあえず現時点では全体の流れを理解しておいて下さい。
Material DesignThemesをNuget経由でインストールします。
ShowMeTheXAML.MSBuildをNuget経由でインストールします。
App.xamlにMaterial Designテーマを適用するためにコードを数行追加します。
Windows.xaml にMaterial Designテーマを適用するためにコードを1行だけ追加します。
自作ユーザコントロールの xaml にMaterial Designテーマを適用するためにコードを数行追加します。
なお、詳細についてはGitHub上の MaterialDesignInXAMLページ に記載されていますが、本記事で紹介する内容もこれと同じです。
2024年1月現在においてFrameworkは.NET 7.0 までしか記載がありませんが、.本記事では Visual Studio 2022、.NET 8.0 の環境を前提に説明します。
インストール手順
Material DesignThemes のインストール
Nugetの検索入力に次のキーワードを入力し、表示された中から「MaterialDesignThemes」を選んでインストールします。
MaterialDesignThemes
ShowMeTheXAML.MSBuildのインストール
次のキーワードを入力し、表示された中から「ShowMeTheXAML.MSBuild」を選んでインストールします。
ShowMeTheXAML.MSBuild
App.xamlにMaterial Designテーマを適用
App.xaml の <Application>タグ内に、次の1行を追加します。
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
App.xaml の <Application.Resource> タグ内に、次の行を追加します。
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
NugetでインストールしたMaterialDesignThemesのバージョンが4.9 を利用されている方は、4行目が
~省略~component/Themes/MaterialDesignTheme.Defaults.xaml" />
になっていると思います。
バージョン5.0の登場で MaterialDesignTheme.Defaults.xaml が参照できなくなったため、バージョンアップの際は "MaterialDesignTheme" を "MaterialDesign2" または "MaterialDesign3" に書き換えて下さい。
MainWindow.xamlにMaterial Designテーマを適用
MainWindow.xaml の <Winodw> タグ内に、次の行を追加します。この時、1行目の記述(参照設定)は必須ですが、2行目以降は無くても構いません。但しこうしておくとアプリ全体のテキストスタイルを一括で調整できるので便利です。
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.FontWeight="Medium"
TextElement.FontSize="14"
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
自作ユーザーコントロールにMaterial Designテーマを適用(必要に応じて)
自作ユーザーコントロールに対しては、<UserControl>タグの中に次の1行を追加します。これで、MainWindowで指定した設定(App.xamlやMainWindow.xamlで設定されたテーマやフォントスタイル)が自動的に自作ユーザーコントロールに反映されるようになります。
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ユーザーコントロールに別のMaterial Design テーマを設定する方法
特定の自作ユーザーコントロールに対しては、MainWindowとは別のMaterial Design テーマを設定したい場合は、App.xaml や MainWindow.xaml に追加した内容と同じ内容を追加します。
<UserControl>タグの中に次の内容を追加します(MainWindow.xamlに追加した内容と同じ)。
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.FontWeight="Medium"
TextElement.FontSize="14"
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
<UserControl> タグの中に次の内容を追加します(App.xamlに追加した内容と同じ)。
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
既に<UserControl.Resouce>タグが存在する場合は、元のスタイルとMaterial Design のデザインが競合しないように気を付けて下さい。
また、上記の内容を追加すると「エラー XDG0046 すべてのディクショナリ エントリにキーが関連付けられている必要があります。 」というエラーが発生しますが、ResourceDictionary にキーを設定(例:x:Key="Theme")すれば回避できます。
この場合、 <ResourceDictionary x:Key="Theme">という具合に任意の名前を付与すれば 解消できます。
<ResourceDictionary x:Key="Theme">
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
カラーテーマを変更する方法
<Application.Resource>タグや <UserControl.Resource>タグに追加した中に<materialDesign> タグがありますが、ここでカラーテーマが設定されています。
BaseThemeは文字通りベースとなる配色で、Lightと Dark の2通りが選択可能です。そのうえで、PrimaryColorとSecondaryColor が20種類の中から選択できるようになっており、これらを組み合わせることでカラーテーマをカスタマイズできます。
MainWindowとユーザーコントロールの一方だけに追加した場合の挙動
MainWindow.xaml(App.xaml含む)と自作ユーザーコントロールの両方に追加しましたが、どちらか片方だけ追加した場合はどうなるかを調べてみました。
MainWindown.xaml に追加した場合、その傘下にあるすべてのコントロール(自作ユーザーコントロール含む)に対してデザインが反映されました。
一方、自作ユーザーコントロールにだけ追加した場合は、その自作コントロール内のコントロールにのみデザインが反映されました。
但し、Material Design Xaml Toolkitで追加されたタグやプロパティ(materialDesign:~など)を使ったデザインについては、使う場所で xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" を追加しておかないと参照エラーになってしまいます。
以上のことから、Material Design Xaml Toolkit の拡張タグやプロパティを使わず、WPF標準のコントロールだけを使うのであれば MainWindow.xaml への追加だけで、全てのコントロール(自作ユーザーコントロール含む)にデザインが反映されますが、拡張タグやプロパティを使うのであれば、自作ユーザーコントロールにも追加が必要です。
使い方
Material Design Xaml ToolKit でインストールされたコントロールが左に表示されるので、これをレイアウトエディタにドラッグ&ドロップして使用します。
ただ1点注意点があって、GridやCanvasを使ったMarginや座標によるレイアウト指定とはあまり相性が良くありません。これらを使って作成したレイアウトの場合、コントロールの一部が見切れることが多く、微調整が非常に面倒です。
出来るだけ、StackPanelやDockPanel、ScrollViewなど相対座標が前提のコンテナ系コントロールを使うことをお勧めします。
WPF標準コントロールを使ったデザイン
WPF標準のコントロールについても自動的にモダンなデザインに変更されています。WPF標準コントロールを画面に一通り配置して実行した結果です。
<Window x:Class="MaterialDesignTest.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:MaterialDesignTest"
mc:Ignorable="d"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.FontWeight="Medium"
TextElement.FontSize="14"
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TabControl>
<TabItem Header="TabItem">
<DockPanel Background="#FFE5E5E5" LastChildFill="True">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Height="60">
<Button Content="Button" HorizontalAlignment="Left" Margin="10"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock"
VerticalAlignment="Center" Margin="10"/>
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBox"
Margin="10" Width="230"/>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" />
<RadioButton Content="RadioButton" HorizontalAlignment="Left"
Height="23" Margin="10" />
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Height="60" Margin="10" >
<ProgressBar HorizontalAlignment="Left" Height="23" Width="165" Margin="10" />
<ComboBox HorizontalAlignment="Left" Width="210" Margin="10"/>
<Slider Width="234" Margin="10" Height="26"/>
<DatePicker HorizontalAlignment="Left" VerticalAlignment="Top"
Height="30" Width="31"/>
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="71*"/>
<ColumnDefinition Width="71*"/>
</Grid.ColumnDefinitions>
<DataGrid ItemsSource="{Binding Data}" Width="400" Margin="20"/>
<ListBox ItemsSource="{Binding Items}" Width="300" Margin="20"
Background="AliceBlue" VerticalAlignment="Center"
HorizontalAlignment="Center" Height="152" Grid.Column="1"/>
</Grid>
</StackPanel>
</DockPanel>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
</Window>
WPF標準コントロールで拡張プロパティを使用
WPF標準のコントロールに対して、Material Design Xaml Toolkit の拡張プロパティを設定してみました。これだけでもかなり見栄えが良くなったのではないでしょうか。
<Window x:Class="MaterialDesignTest.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:MaterialDesignTest"
mc:Ignorable="d"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
Background="{DynamicResource MaterialDesignPaper}"
TextElement.FontWeight="Medium"
TextElement.FontSize="14"
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TabControl
materialDesign:ColorZoneAssist.Mode="SecondaryDark"
Style="{StaticResource MaterialDesignFilledTabControl}">
<TabItem Header="TabItem">
<DockPanel Background="#FFE5E5E5" LastChildFill="True">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Height="60">
<Button
Margin="2,0"
materialDesign:ButtonProgressAssist.IsIndeterminate="True"
materialDesign:ButtonProgressAssist.IsIndicatorVisible="True"
materialDesign:ButtonProgressAssist.Value="-1"
Content="Indeterminate"
IsEnabled="{Binding DataContext.ControlsEnabled,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
Style="{StaticResource MaterialDesignRaisedButton}" />
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBlock"
VerticalAlignment="Center" Margin="10"/>
<TextBox
Width="150"
materialDesign:HintAssist.FloatingScale="0.70"
materialDesign:HintAssist.Hint="名前"
materialDesign:TextFieldAssist.TextBoxViewMargin="2"
FontSize="20"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="山田太郎" />
<CheckBox
Content="CheckBox"
IsChecked="True"
Style="{StaticResource MaterialDesignFilterChipPrimaryCheckBox}" />
<ToggleButton
IsChecked="True"
Style="{StaticResource MaterialDesignSwitchToggleButton}"
ToolTip="MaterialDesignSwitchToggleButton" />
<materialDesign:PackIcon Kind="NoteSearchOutline" Height="30" Width="30"
VerticalAlignment="Center" Margin="10"/>
<materialDesign:PackIcon Kind="FolderRefreshOutline"
VerticalAlignment="Center" Height="30" Width="30" Margin="10"/>
<Button
Margin="10"
IsEnabled="{Binding DataContext.ControlsEnabled,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
Style="{StaticResource MaterialDesignFloatingActionMiniSecondaryButton}"
ToolTip="MaterialDesignFloatingActionMiniSecondaryButton">
<materialDesign:PackIcon
Kind="Alarm" />
</Button>
<Button
Margin="10"
Width="40" Height="40"
materialDesign:ButtonProgressAssist.IsIndeterminate="True"
materialDesign:ButtonProgressAssist.IsIndicatorVisible="True"
materialDesign:ButtonProgressAssist.Value="-1"
Content="{materialDesign:PackIcon DotsHorizontal}"
IsEnabled="{Binding DataContext.ControlsEnabled,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
Style="{StaticResource MaterialDesignFloatingActionButton}" />
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Height="60" Margin="10" >
<ProgressBar
Width="40" Height="40"
Margin="10"
IsIndeterminate="True"
x:Name="DeterminateCircularProgress"
Style="{StaticResource MaterialDesignCircularProgressBar}" />
<ComboBox
Width="256"
materialDesign:HintAssist.Hint="Validation test (editable)"
materialDesign:TextFieldAssist.HasClearButton="True"
IsEditable="True"
ItemsSource="{Binding ShortStringList}"
Style="{StaticResource MaterialDesignFilledComboBox}">
<ComboBox.SelectedItem>
<Binding
Mode="TwoWay"
Path="SelectedValidationFilled"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
</Binding.ValidationRules>
</Binding>
</ComboBox.SelectedItem>
</ComboBox>
<Slider
IsSelectionRangeEnabled="True"
Margin="10"
Width="250"
Maximum="50"
Minimum="0"
Orientation="Horizontal"
SelectionEnd="20"
SelectionStart="0"
TickFrequency="5"
TickPlacement="BottomRight"
Value="10" />
<DatePicker
Width="140"
materialDesign:DatePickerAssist.OutlinedBorderActiveThickness="3"
materialDesign:DatePickerAssist.OutlinedBorderInactiveThickness="3"
materialDesign:HintAssist.FloatingOffset="0,-23"
materialDesign:HintAssist.HelperText="Helper text"
materialDesign:HintAssist.Hint="Pick Date"
Style="{StaticResource MaterialDesignOutlinedDatePicker}" />
</StackPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="71*"/>
<ColumnDefinition Width="71*"/>
</Grid.ColumnDefinitions>
<DataGrid ItemsSource="{Binding Data}" Width="400" Margin="20"/>
<ListBox ItemsSource="{Binding Items}" Width="300" Margin="20"
Background="AliceBlue" VerticalAlignment="Center"
HorizontalAlignment="Center" Height="152" Grid.Column="1"/>
</Grid>
</StackPanel>
</DockPanel>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
</Window>
Material Design Xaml In ToolKit拡張コントロール
今回紹介したものはWPF標準コントロールをカスタマイズするような形でしたが、今回紹介しきれない多くのコントロールが存在しています。これらについてはまた別の記事で紹介したいと思います。
他にどのような機能があるかについては、下記の公式動画をご覧ください。
デモ版(MaterialDesignDemo)の活用について
Material Design の種類が豊富なので、全てを把握するのは大変です。そんな時の為にデモプログラムが用意されています。
このデモプログラムには、各種コントロールごとに適用可能なデザインと、それを実現するためのXAMLが取得できるようになっているため、リファレンスとして利用できます。
デモ版の入手方法
GitHubの MaterialDesignInXAMLページ を表示し、少しスクロールすると[DemoApp.zip」が見つかりますので、これをクリックしてデモ版をダウンロードして下さい。
DemoApp.zip を解凍すると、次のようなフォルダ構成になっています。それぞれのFramewrokごとにデモが用意されていますので、ご自身の環境に合ったデモを実行して下さい。私の場合は .NET 8.0 なので、 net7.-windows を実行しました。
実行すると下記の警告画面が表示されますが、気にせず実行しましょう。
デモ版の使い方
デモプログラムを起動すると、次の画面が表示されます。左上のメニューアイコンをクリックすると、コントロールの一覧が表示されるので、任意のコントロールを選択します。
選択したコントロールごとに、そのコントロールを用いた様々なデザインが表示されます。
使いたいデザインが見つかったら、 </> マークをクリックして下さい。そのデザインを実現するためのXAMLが表示されますので、COPYボタンでコピーし、自作プログラムの任意のXAMLに張り付けてください。
デモ画面のメニューから Icon Pack を選択すると、下記のようなアイコン検索画面が表示されます。ここでアイコンを検索すると画面下にXAMLが表示されるので、これをコピペして使うことが出来ます。
デモ版で使われているナビゲーションメニューの実現方法
デモ版で使われているナビゲーションメニューの実現方法については「 【WPF】 Material Design In XAML Tool Kit を使ったナビゲーションメニュー4選」の記事で紹介していますので、興味のある方はご一読ください。
まとめ
Googleが提唱するデザインルール「Material Design」は、スマホやタブレットをはじめ、数多くのWebサイト/Webアプリでも採用されています。
そして、これを WPFで簡単に実現できるようにしたものが今回紹介した Material Design Xaml In Toolkit です。
Material Design Xaml In Toolkit を使えば、WebUIと比べて見劣りするWPFのUIデザインを、見栄え良くモダンなデザインに変えてくれます。
Material Designに関する知識が無くても、Nugetで2つのライブラリをインストールし、App.xamlとMainWindow.xamlに少し追加するだけで、見違えるようなデザインが手に入ります。
もしWPFのデザインで物足りなくなった方は、是非この記事を参考にしてチャレンジしてみてください。
コメント