0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Material Design Themes】ComboBoxでPrimaryColorを切り替える

Posted at

はじめに

Material Design ThemesのPrimaryColorをコンボボックスで切り替えるためのユーザーコントロールを作成したので備忘録として公開します。この手順で同様にSecondaryColorを切り替えるためのユーザーコントロールも作成できます。
MVVMパターンで記述するため、CommunityToolkit.Mvvmも合わせて使用します。
image.png

前回、トグルボタンでダークモードに切り替えるためのユーザーコントロールを作成したので、説明が重複しますがご了承ください。前回の続きからの方は、プロジェクトフォルダにConvertersフォルダを追加して、PrimarySelectorViewModel.csの項目まで飛ばしてください。

情報

アプリケーション

  • アプリケーション:WPFアプリケーション
  • ターゲットフレームワーク:.Net 8.0

ライブラリ

  • CommunityToolkit.Mvvm 8.2.2
  • MaterialDesignThemes 5.0.0
  • MaterialDesignColors 3.0.0

プロジェクトの作成

プロジェクト名をMaterialDesignAppsとしてプロジェクトを作成しました。作成が完了したら、画像のようにフォルダを作成してください。前回の続きからの方は、Convertersフォルダを追加してください。
image.png

フォルダ作成ができたらMainWindowをViewsフォルダに移動してください。このとき、MainWindowの名前空間をMaterialDesignApps.Viewsに変更してください。また、App.xamlのStartupUriをViews\MainWindow.xamlに変更してください。

ライブラリのインストール

NuGetパッケージの管理からCommunityToolkit.MvvmMaterialDesignThemesMaterialDesignColorsをインストールしてください。

App.xamlの設定

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}"を追加します。

Views\MainWindow.xaml
<Window ...
    Style="{StaticResource MaterialDesignWindow}">
    ...
</Window>

確認

先程のApp.xamlBaseThemeDarkに変更して、アプリケーションを起動してください。
これまでの作業に問題がなければ、背景が黒色のアプリケーションが起動されます。
これで、WPFアプリケーションでMaterial Design Themesを使用する準備が整いました。

ThemeHelper.cs

Helpersフォルダに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を作成します。

ViewModels\PrimarySelectorViewModel.cs
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に変換するためのコンバーターを作成します。

Converters\PrimaryToBrush.cs
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フォルダにユーザーコントロールを作成します。作成した時点で一度ビルドを行います。

Controls\PrimarySelector.xaml
<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にコントロールを配置したら完了です。

Views\MainWindow.xaml
<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をコンボボックスで切り替えるためのユーザーコントロールを作成可能です。
コードの使用によって生じるいかなる損害も、作者は一切責任を負いません。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?