プロジェクトの作成
1)
同等のものをWinUI 3
で作成します。
以前のWinUIのステップを読み飛ばした方はこのステップ11-4
も読み飛ばしてください。
2)
新しいプロジェクトの作成で、最近使用したプロジェクトテンプレートから
空のアプリ、パッケージ化 (デスクトップのWinUI 3)
を選択して次へ
ボタンを押します。
プロジェクト名にDarkLightMode_2
を入力して作成します。
3)
ソリューションエクスプローラーでプロジェクトをダブルクリックし、csprojを開き、PropertyGroup
に以下を追加します。
<Nullable>enable</Nullable>
<WindowsPackageType>None</WindowsPackageType>
プロジェクト直下のPackage.appxmanifest
を削除します。
4)
ソリューションエクスプローラーでソリューションを右クリックし、ソリューションの NuGet パッケージの管理
を選択します。
更新があればアップデートしておきます。
5)
App.xaml.cs
を開き、OnLaunched
メソッドのm_window
のActivate
メソッド呼び出しに?
を付け、
m_window
定義の型のWindow
に?
を付けます。
6)
ソリューションエクスプローラーでProperties
フォルダの中のlaunchSettings.json
を開き、
(Package)
の項目を削除します。
launchSettings.json
を保存します。
デバッグ実行のボタンが Unpackaged になっていることを確認します。
画面作成
1)
WPFのDarkLightMode_1
も開いておきます。
WPF側のMainWindow.xaml
のNavigationView
を丸々コピーします。
そしてWinUI側のMainWindow.xaml
のStackPanel
に上書き貼り付けし、
Ctrl
+ H
で置換ダイアログを表示し、ui:
を空欄に全置換します。
ScrollViewer
のMargin
を10
に修正します。
Frame
のPadding
プロパティを削除します。
2)
プロジェクト直下にPages
フォルダを作成します。
Pages
フォルダを右クリックし、追加
> 新しい項目
を選択します。
新しい項目の追加
ダイアログで左のツリーからWinUI
を選択し、空白のページ (WinUI 3)
を選択し、
名前にHomePage
を入力して追加
ボタンを押します。
同様に以下のページを追加します。
- EditPage
- SettingsPage
- BlankPage
Pages
フォルダを右クリックし、追加
> クラス
でNaviPages
クラスを追加します。
WPF側のNaviPages.cs
を開き、usingディレクティブとNaviPageId
列挙定義、NaviPages
クラスをWinUI側にコピー&貼り付けします。
名前空間の部分(namespace DarkLightMode_1.Pages
)までコピーしないよう注意してください。
3)
HomePage.xaml
とEditPage.xaml
のTextBlock
をコピーしてきます。
4)
MainWindow.xaml
のWindow
にxmlns:pg=
と入力し、page
と入力します。
そうすると候補が1つに絞り込まれるのでEnterで確定します。
Home
のNavigationViewItem
のTag
指定を以下のように修正します。
<NavigationViewItem Icon="Home"
Content="ホーム"
Tag="{x:Static pg:NaviPageId.Home}"
IsSelected="True" />
<NavigationViewItem Icon="Home"
Content="ホーム"
IsSelected="True">
<NavigationViewItem.Tag>
<pg:NaviPageId>Home</pg:NaviPageId>
</NavigationViewItem.Tag>
</NavigationViewItem>
Edit
のNavigationViewItem
のTag
指定も同様に修正します。
<NavigationViewItem Icon="Edit"
Content="編集">
<NavigationViewItem.Tag>
<pg:NaviPageId>Edit</pg:NaviPageId>
</NavigationViewItem.Tag>
</NavigationViewItem>
5)
NavigationView
のNaviView_SelectionChangedにカーソルを置いてF12
キーを押します。
myButton_Click
メソッドは削除します。
6)
プロジェクト直下にDialog
フォルダを作成し、その中にMsgDialog
クラスを作成します。
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Threading.Tasks;
namespace DarkLightMode_2.Dialog
{
/// <summary>
/// メッセージダイアログ
/// </summary>
internal static class MsgDialog
{
/// <summary>
/// エラー表示
/// </summary>
/// <param name="root"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static async Task ErrorAsync(XamlRoot root, string msg)
{
var dlg = new ContentDialog
{
Title = "エラー",
Content = msg,
CloseButtonText = "OK",
};
dlg.XamlRoot = root;
// ダイアログ表示
await dlg.ShowAsync();
}
}
}
7)
MainWindow.xaml
のNaviView_SelectionChanged
にasync
を付け、中身に以下を書きます。
try
{
var item = (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)
{
await MsgDialog.ErrorAsync(Content.XamlRoot, ex.ToString());
}
PageNavigate
メソッドを追加します。
/// <summary>
/// ページ切り替え
/// </summary>
/// <param name="id">ページID</param>
private void PageNavigate(NaviPageId id) =>
ContentFrame.Navigate(NaviPages.Index[id]);
エラー箇所はいつもの対処です。
設定ページコントロール記述
SettingsPage.xaml
のGrid
を以下に置き換えます。
<Page.Resources>
<Style TargetType="ToggleSwitch">
<Setter Property="Margin"
Value="0,5" />
</Style>
<!-- テーマラジオボタンスタイル -->
<Style x:Key="ThemeRadioStyle"
TargetType="RadioButton"
BasedOn="{StaticResource DefaultRadioButtonStyle}">
<Setter Property="GroupName"
Value="Theme" />
</Style>
</Page.Resources>
<StackPanel>
<TextBlock Text="テーマ"
Style="{StaticResource TitleTextBlockStyle}" />
<RadioButton x:Name="ThemeSystem"
Content="Windows テーマを使用"
Style="{StaticResource ThemeRadioStyle}" />
<RadioButton x:Name="ThemeLight"
Content="ライト"
Style="{StaticResource ThemeRadioStyle}" />
<RadioButton x:Name="ThemeDark"
Content="ダーク"
Style="{StaticResource ThemeRadioStyle}" />
<TextBlock Text="※アプリ再起動後に有効"
Margin="0,10,0,0"/>
<TextBlock Text="その他"
Style="{StaticResource TitleTextBlockStyle}"
Margin="0,20,0,0" />
<ToggleSwitch x:Name="Option1"
Header="何かのオプション1" />
<ToggleSwitch x:Name="Option2"
Header="何かのオプション2" />
</StackPanel>
設定読み書き
1)
App.xaml.cs
を開き、以下を追加します。
/// <summary>
/// アプリケーション設定ファイル名
/// </summary>
public const string SettingsFileName = "settings.json";
/// <summary>
/// アプリケーション設定ファイルパス取得
/// </summary>
/// <returns></returns>
/// <exception cref="DirectoryNotFoundException"></exception>
public static string GetSettingsFilePath()
{
string? appPath = AppContext.BaseDirectory;
if (appPath is null)
{
throw new DirectoryNotFoundException("実行ファイルのパス取得失敗");
}
return System.IO.Path.Combine(appPath, SettingsFileName);
}
2)
WPFのプロジェクトからSettings
フォルダをコピーし、WinUIのプロジェクトに貼り付けます。
WinUIプロジェクトに貼り付けたSettings.cs
, SettingsReader.cs
, SettingsWriter.cs
の名前空間を修正します。
namespace DarkLightMode_2.Settings
3)
App.xaml.cs
を編集します。
コンストラクタにSetAppTheme
メソッド呼び出しを追加します。
public App()
{
this.InitializeComponent();
+ SetAppTheme();
}
SetAppTheme
メソッドは以下のように書きます。
/// <summary>
/// 設定ファイルを読み込みテーマ適用
/// </summary>
private void SetAppTheme()
{
try
{
var sr = new Settings.SettingsReader(App.GetSettingsFilePath());
var settings = sr.ReadFromFile();
if (settings.Theme == "Dark")
{
App.Current.RequestedTheme = ApplicationTheme.Dark;
}
else if (settings.Theme == "Light")
{
App.Current.RequestedTheme = ApplicationTheme.Light;
}
}
catch
{
}
}
設定ページのイベント処理
1)
Settings.xaml
を開き、
Page
のLoaded
, LostFocus
, Unloaded
イベントハンドラを作成します。
Loaded
の処理にasync
を付け足して中に以下を書きます。
try
{
ReadSettings();
}
catch (Exception ex)
{
await MsgDialog.ErrorAsync(Content.XamlRoot, ex.ToString());
}
ReadSettings
メソッドは以下のように編集します。
/// <summary>
/// 設定読み込み
/// </summary>
private void ReadSettings()
{
var sr = new Settings.SettingsReader(App.GetSettingsFilePath());
var settings = sr.ReadFromFile();
SetThemeSettings(settings.Theme);
Option1.IsOn = settings.Option1;
Option2.IsOn = settings.Option2;
}
/// <summary>
/// テーマ文字列を画面の設定に反映
/// </summary>
/// <param name="theme"></param>
private void SetThemeSettings(string? theme)
{
if (theme == "Dark")
{
ThemeDark.IsChecked = true;
}
else if (theme == "Light")
{
ThemeLight.IsChecked = true;
}
else
{
ThemeSystem.IsChecked = true;
}
}
2)
LostFocus
の処理にasync
を付け足して中に以下を書きます。
try
{
WriteSettings();
}
catch (Exception ex)
{
await MsgDialog.ErrorAsync(Content.XamlRoot, ex.ToString());
}
WriteSettings
メソッドは以下のように編集します。
/// <summary>
/// 設定書き込み
/// </summary>
var settings = new Settings.Settings
{
Option1 = Option1.IsOn,
Option2 = Option2.IsOn,
Theme = GetThemeString(),
};
var sw = new Settings.SettingsWriter(App.GetSettingsFilePath());
sw.WriteToFile(settings);
/// <summary>
/// テーマ設定の文字列取得
/// </summary>
/// <returns></returns>
private string? GetThemeString()
{
if (ThemeDark.IsChecked == true)
{
return "Dark";
}
else if (ThemeLight.IsChecked == true)
{
return "Light";
}
else
{
return null;
}
}
3)
Unloaded
の処理にasync
を付け足して中に以下を書きます。
try
{
WriteSettings();
}
catch (Exception ex)
{
await MsgDialog.ErrorAsync(Content.XamlRoot, ex.ToString());
}