Chapter 38

ステップ11-1: ダークモード(ダークテーマ)

Apterygiformes-zenn
Apterygiformes-zenn
2022.01.27に更新

概要

配色テーマの黒基調/白基調に対応します。

プロジェクトの作成

新しいプロジェクトの作成でWPFアプリケーションを、プロジェクト名:DarkLightMode_1、フレームワーク:.NET 6.0で作成してください。

システムの配色モードを適用

プロジェクトを右クリックし、NuGetパッケージの管理を選択します。

参照タブを選択し、検索ボックスにmodernwpfuiと入力、ModernWpfUIをインストールします。

App.xamlxmlns:ui=~ResourceDictionaryを追加します。

App.xaml
 <Application x:Class="DarkLightMode_1.App"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:DarkLightMode_1"
+             xmlns:ui="http://schemas.modernwpf.com/2019"
              StartupUri="MainWindow.xaml">
     <Application.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ui:ThemeResources />
+                <ui:XamlControlsResources />
+                <!-- Other merged dictionaries here -->
+            </ResourceDictionary.MergedDictionaries>
+            <!-- Other app resources here -->
+        </ResourceDictionary>
     </Application.Resources>
 </Application>

MainWindow.xamlxmlns:ui=~ui:WindowHelper.~を追加します。

MainWindow.xaml
 <Window x:Class="DarkLightMode_1.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:DarkLightMode_1"
+        xmlns:ui="http://schemas.modernwpf.com/2019"
+        ui:WindowHelper.UseModernWindowStyle="True"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800">
     <Grid>
 
     </Grid>
 </Window>

ソリューションエクスプローラーでプロジェクトをダブルクリックしてcsprojを開き、
TargetFrameworkの値をnet6.0-windows10.0.18362.0に編集します。

TargetFramework
net6.0-windows10.0.18362.0

配色モードの動作確認

メニューのビルド > ソリューションのリビルドを実行してから緑三角でデバッグ実行します。

Windowsの配色モード(ダーク/ライト)に連動して画面の配色が変わります。

ダークモードです。

ライトモードです。

OSの配色モードにお任せでいいなら対応はこれで完了です。
デバッグ実行を終了します。

画面の作成

アプリ上から配色モードの切り替えをできるようにします。
ついでにNavigationViewという、ページ切り替えのコントロールも使ってみます。

1)

Windowの中のGridを削除し、<ui:NavigationView />を追加します。

↓↓↓↓↓

NavigationViewの名前にNaviViewを設定し、以下のプロパティを設定します。

プロパティ 設定値
IsBackButtonVisible Collapsed
IsPaneToggleButtonVisible False
PaneDisplayMode Left

MenuItemsプロパティの...ボタンを押します。

ドロップダウンから<その他の型...>を選択します。

検索ボックスにviewitemを入力して候補を絞り込みます。
NavigationViewItemを選択し、OKボタンを押します。

追加ボタンを押し、OKボタンを押します。

↓↓↓↓↓

<ui:NavigationViewItem />を以下のように編集します。

<ui:NavigationViewItem Icon="Home" Content="" Tag="" />

行を選択しCtrl + Xで切り取ります。

Ctrl + Vを数回押して貼り付けます。

本来はここで1つ1つ内容を作っていきますが、作業を短縮します。
貼り付けたNavigationViewItemを削除し、代わりに以下を貼り付けてください。

<ui:NavigationViewItem Icon="Home"
                       Content="ホーム"
                       Tag="" />
<ui:NavigationViewItem Icon="Edit"
                       Content="編集"
                       Tag="" />
<ui:NavigationViewItem Icon="Save"
                       Content="保存"
                       Tag="" />
<ui:NavigationViewItem Icon="Keyboard"
                       Content="キーボード"
                       Tag="" />
<ui:NavigationViewItem Icon="Library"
                       Content="ライブラリ"
                       Tag="" />
<ui:NavigationViewItem Icon="Link"
                       Content="リンク"
                       Tag="" />
<ui:NavigationViewItem Icon="List"
                       Content="一覧A"
                       Tag="" />
<ui:NavigationViewItem Icon="Bullets"
                       Content="一覧B"
                       Tag="" />
<ui:NavigationViewItem Icon="Mail"
                       Content="メール"
                       Tag="" />
<ui:NavigationViewItem Icon="Send"
                       Content="送信"
                       Tag="" />
<ui:NavigationViewItem Icon="Map"
                       Content="地図"
                       Tag="" />
<ui:NavigationViewItem Icon="Manage"
                       Content="管理"
                       Tag="" />
<ui:NavigationViewItem Icon="Message"
                       Content="メッセージ"
                       Tag="" />
<ui:NavigationViewItem Icon="Print"
                       Content="印刷"
                       Tag="" />
<ui:NavigationViewItem Icon="Repair"
                       Content="修復"
                       Tag="" />
<ui:NavigationViewItem Icon="Account"
                       Content="アカウント"
                       Tag="" />
<ui:NavigationViewItem Icon="People"
                       Content="ユーザー"
                       Tag="" />
<ui:NavigationViewItem Icon="Contact"
                       Content="連絡先A"
                       Tag="" />
<ui:NavigationViewItem Icon="Contact2"
                       Content="連絡先B"
                       Tag="" />
<ui:NavigationViewItem Icon="AddFriend"
                       Content="ユーザーの追加"
                       Tag="" />
<ui:NavigationViewItem Icon="Attach"
                       Content="添付ファイル"
                       Tag="" />
<ui:NavigationViewItem Icon="Audio"
                       Content="ミュージック"
                       Tag="" />
<ui:NavigationViewItem Icon="BrowsePhotos"
                       Content="検索A"
                       Tag="" />
<ui:NavigationViewItem Icon="Find"
                       Content="検索B"
                       Tag="" />
<ui:NavigationViewItem Icon="Calculator"
                       Content="計算"
                       Tag="" />
<ui:NavigationViewItem Icon="Calendar"
                       Content="カレンダー"
                       Tag="" />
<ui:NavigationViewItem Icon="Camera"
                       Content="カメラ"
                       Tag="" />
<ui:NavigationViewItem Icon="Character"
                       Content="文字A"
                       Tag="" />
<ui:NavigationViewItem Icon="Font"
                       Content="文字B"
                       Tag="" />
<ui:NavigationViewItem Icon="Clock"
                       Content="時刻"
                       Tag="" />
<ui:NavigationViewItem Icon="Globe"
                       Content="ネットワーク"
                       Tag="" />
<ui:NavigationViewItem Icon="Help"
                       Content="ヘルプ"
                       Tag="" />
<ui:NavigationViewItem Icon="Favorite"
                       Content="お気に入り"
                       Tag="" />
<ui:NavigationViewItem Icon="Filter"
                       Content="フィルタ"
                       Tag="" />
<ui:NavigationViewItem Icon="Flag"
                       Content="フラグ"
                       Tag="" />
<ui:NavigationViewItem Icon="Delete"
                       Content="ごみ箱"
                       Tag="" />

貼り付けたらHomeNavigationViewItemを選択し、IsSelectedプロパティをONにします。

2)

プロジェクト直下にPagesフォルダを作成します。
Pagesフォルダを右クリックし、追加 > クラスNaviPagesクラスを追加します。

Pagesフォルダを右クリックし、追加 > ページ (WPF)で以下のページを追加します。

  • HomePage
  • EditPage
  • SettingsPage
  • BlankPage

Settingsページはテーマ切り替えのコントロール配置用です。
HomeEditページはページ切り替えの動作確認用に追加しました。
その他のページは用意するのが大変なので全部Blankページを表示します。

ページを追加したらNaviPages.csを編集します。

各ページにIDを用意します。
本来は各ページごとにIDを用意しますが、サンプルなので一部だけ用意します。

/// <summary>
/// ページID
/// </summary>
internal enum NaviPageId
{
    None,
    Settings,

    Home,
    Edit,
    Save,
    Keyboard,
}

ページIDと実際のページの関連付けを行います。

/// <summary>
/// ページ管理
/// </summary>
internal class NaviPages
{
    public static readonly IReadOnlyDictionary<NaviPageId, Type> Index =
        new Dictionary<NaviPageId, Type>
        {
            { NaviPageId.Home, typeof(Pages.HomePage) },
            { NaviPageId.Edit, typeof(Pages.EditPage) },
            { NaviPageId.Settings, typeof(Pages.SettingsPage) },
            // 空ページ
            { NaviPageId.None, typeof(Pages.BlankPage) },
        };
}

3)

HomePage.xamlGrid内に以下を追加します。

<TextBlock Text="Home Home Home" />

EditPage.xamlも同様に以下を追加します。

<TextBlock Text="Edit Edit Edit" />

4)

MainWindow.xamlWindowxmlns:pg=と入力し、pageと入力します。
そうすると候補が1つに絞り込まれるのでEnterで確定します。

NavigationViewItemTagにページIDを設定します。
HomeNavigationViewItemTag{x:Static pg:NaviPageId.と入力し、候補のHomeを選択します。

EditNavigationViewItemTagも同様にNaviPageId.Editを指定します。

pg:NaviPageId.Homepg:NaviPageId.Editpg
Windowに書いたxmlns:pg="clr-namespace:DarkLightMode_1.Pages"
xmlns:pgと対応しています。
ここをxmlns:abcde="clr-namespace:DarkLightMode_1.Pages"と書いていたら
Tagの方は{x:Static abcde:NaviPageId.Home}のように書きます。

NavigationView.MenuItemの下に以下を追加します。

<ScrollViewer Margin="0,0,0,10">
    <!-- 切り替わるページ部分 -->
    <ui:Frame x:Name="ContentFrame"
                Padding="10,10,10,5" />
</ScrollViewer>


デザイナーの画面イメージの右側の白い部分が切り替わる部分です。

5)

MainWindow.xaml.csに以下を追加します。

using ui = ModernWpf.Controls;

NavigationViewSelectionChangedイベントのイベントハンドラを作成します。

↓↓↓↓↓

PageNavigateメソッドを作成します。
ContentFrameは先ほどNavigationViewに追加した、Frameコントロールです。
引数で受け取ったページIDに対応するページを設定します。

/// <summary>
/// ページ切り替え
/// </summary>
/// <param name="id">ページID</param>
private void PageNavigate(NaviPageId id) =>
    ContentFrame.Navigate(NaviPages.Index[id]);
📘他の書き方
private void PageNavigate(NaviPageId id)
{
    ContentFrame.Navigate(NaviPages.Index[id]);
}

NaviView_SelectionChangedに以下を書きます。

try
{
    var item = (ui.NavigationViewItem)args.SelectedItem;
    NaviView.Header = item?.Content.ToString();

    if (args.IsSettingsSelected)
    {
        // 設定ページ表示
        PageNavigate(NaviPageId.Settings);

        return;
    }
    string? tag = item?.Tag?.ToString();
    if (Enum.TryParse(tag, out NaviPageId id))
    {
        // 対応するページ表示
        PageNavigate(id);
    }
    else
    {
        // 空ページ表示
        PageNavigate(NaviPageId.None);
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.ToString());
}

ページ切り替えの動作確認

実行してみます。

編集を選択します。ページが切り替わりました。

復習ポイント

  • ダークモード/ライトモード