はじめに
Material Design ThemesのPrimaryColorをコンボボックスで切り替えるためのユーザーコントロールを作成したので備忘録として公開します。この手順で同様にSecondaryColorを切り替えるためのユーザーコントロールも作成できます。
MVVMパターンで記述するため、CommunityToolkit.Mvvmも合わせて使用します。
前回、トグルボタンでダークモードに切り替えるためのユーザーコントロールを作成したので、説明が重複しますがご了承ください。前回の続きからの方は、プロジェクトフォルダにConverters
フォルダを追加して、PrimarySelectorViewModel.cs
の項目まで飛ばしてください。
情報
アプリケーション
- アプリケーション:WPFアプリケーション
- ターゲットフレームワーク:.Net 8.0
ライブラリ
- CommunityToolkit.Mvvm 8.2.2
- MaterialDesignThemes 5.0.0
- MaterialDesignColors 3.0.0
プロジェクトの作成
プロジェクト名をMaterialDesignApps
としてプロジェクトを作成しました。作成が完了したら、画像のようにフォルダを作成してください。前回の続きからの方は、Converters
フォルダを追加してください。
フォルダ作成ができたらMainWindow
をViewsフォルダに移動してください。このとき、MainWindow
の名前空間をMaterialDesignApps.Views
に変更してください。また、App.xaml
のStartupUriをViews\MainWindow.xaml
に変更してください。
ライブラリのインストール
NuGetパッケージの管理からCommunityToolkit.Mvvm
とMaterialDesignThemes
、MaterialDesignColors
をインストールしてください。
App.xamlの設定
<Application
x:Class="MaterialDesignApps.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MaterialDesignApps"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="Views\MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Blue" SecondaryColor="Blue"/>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign3.Defaults.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainWindow.xamlの設定
次に、MainWindow.xamlにStyle="{StaticResource MaterialDesignWindow}"
を追加します。
<Window ...
Style="{StaticResource MaterialDesignWindow}">
...
</Window>
確認
先程のApp.xaml
のBaseTheme
をDark
に変更して、アプリケーションを起動してください。
これまでの作業に問題がなければ、背景が黒色のアプリケーションが起動されます。
これで、WPFアプリケーションでMaterial Design Themesを使用する準備が整いました。
ThemeHelper.cs
Helpers
フォルダにThemeHelper.cs
を作成します。
using MaterialDesignColors;
using MaterialDesignThemes.Wpf;
using System.Windows;
namespace MaterialDesignApps.Helpers;
public class ThemeHelper
{
/// <summary>
/// BundledThemeの設定
/// </summary>
public static void SetBundledTheme(BundledTheme bundledTheme)
=> Application.Current.Resources.MergedDictionaries.Add(bundledTheme);
/// <summary>
/// BundledThemeの設定
/// </summary>
public static void SetBundledTheme(BaseTheme baseTheme, PrimaryColor primaryColor, SecondaryColor secondaryColor)
{
SetBundledTheme(new BundledTheme
{
BaseTheme = baseTheme,
PrimaryColor = primaryColor,
SecondaryColor = secondaryColor
});
}
/// <summary>
/// BaseThemeの取得
/// </summary>
public static BaseTheme GetBaseTheme() => GetBundledTheme()?.BaseTheme ?? BaseTheme.Light;
/// <summary>
/// PrimaryColorの取得
/// </summary>
public static PrimaryColor GetPrimaryColor() => GetBundledTheme()?.PrimaryColor ?? PrimaryColor.Blue;
/// <summary>
/// SecondaryColorの取得
/// </summary>
public static SecondaryColor GetSecondaryColor() => GetBundledTheme()?.SecondaryColor ?? SecondaryColor.Blue;
/// <summary>
/// BundledThemeの取得
/// </summary>
public static BundledTheme GetBundledTheme()
{
var bundledTheme = Application.Current.Resources.MergedDictionaries
.OfType<BundledTheme>()
.FirstOrDefault();
return bundledTheme ?? new BundledTheme()
{
BaseTheme = BaseTheme.Light,
PrimaryColor = PrimaryColor.Green,
SecondaryColor = SecondaryColor.Green
};
}
}
PrimarySelectorViewModel.cs
後にPrimarySelector
というユーザーコントロールを作成するので、そのためのViewModelを作成します。
using CommunityToolkit.Mvvm.ComponentModel;
using MaterialDesignApps.Helpers;
using MaterialDesignColors;
using System.Collections.ObjectModel;
namespace MaterialDesignApps.ViewModels;
public partial class PrimarySelectorViewModel : ObservableObject
{
public ObservableCollection<PrimaryColor> PrimaryColors { get; set; }
[ObservableProperty]
PrimaryColor selectedPrimary;
partial void OnSelectedPrimaryChanged(PrimaryColor value)
{
var theme = ThemeHelper.GetBundledTheme();
theme.PrimaryColor = value;
ThemeHelper.SetBundledTheme(theme);
}
public PrimarySelectorViewModel()
{
PrimaryColors = new ObservableCollection<PrimaryColor>((PrimaryColor[])Enum.GetValues(typeof(PrimaryColor)));
var currentPrimary = ThemeHelper.GetPrimaryColor();
SelectedPrimary = currentPrimary;
}
}
PrimaryToBrush.cs
コンボボックスに色の玉を表示するため、PrimaryColorをSolidColorBrushに変換するためのコンバーターを作成します。
using MaterialDesignColors;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace MaterialDesignApps.Converters;
public class PrimaryToBrush : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is PrimaryColor primaryColor)
{
var color = SwatchHelper.Lookup[(MaterialDesignColor)primaryColor];
return new SolidColorBrush(color);
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
PrimarySelector.xaml
Controls
フォルダにユーザーコントロールを作成します。作成した時点で一度ビルドを行います。
<UserControl
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
x:Class="MaterialDesignApps.Controls.PrimarySelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MaterialDesignApps.Controls"
xmlns:vm="clr-namespace:MaterialDesignApps.ViewModels"
xmlns:conv="clr-namespace:MaterialDesignApps.Converters"
mc:Ignorable="d"
d:DesignWidth="200">
<UserControl.Resources>
<ResourceDictionary>
<conv:PrimaryToBrush x:Key="PrimaryToBrush"/>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<vm:PrimarySelectorViewModel/>
</UserControl.DataContext>
<Grid>
<ComboBox
Style="{StaticResource MaterialDesignOutlinedComboBox}"
ItemsSource="{Binding PrimaryColors}"
SelectedItem="{Binding SelectedPrimary}"
materialDesign:HintAssist.Hint="Primary">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse
Width="16"
Height="16"
VerticalAlignment="Center"
Margin="0 0 10 0"
Fill="{Binding Converter={StaticResource PrimaryToBrush}}"/>
<TextBlock
Text="{Binding}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
MainWindow.xaml
MainWindowにコントロールを配置したら完了です。
<Window
xmlns:Controls="clr-namespace:MaterialDesignApps.Controls"
x:Class="MaterialDesignApps.Views.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:MaterialDesignApps.Views"
Style="{StaticResource MaterialDesignWindow}"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="300">
<Controls:PrimarySelector
Width="180"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Window>
起動
起動して、コンボボックスの切り替えて色が切り替われば完了です。
最後に
この記事は備忘録として作成しました。
同様の手順でSecondaryColorをコンボボックスで切り替えるためのユーザーコントロールを作成可能です。
コードの使用によって生じるいかなる損害も、作者は一切責任を負いません。