WPFに最近の技術を色々取り込んで、見た目や開発のしやすさを改善しようとしてみる

1.4K Views

December 09, 24

スライド概要

【登壇者募集中】.NET Conf 2024 後! C# Tokyo カンファレンス - connpass
https://csharp-tokyo.connpass.com/event/334045/
このイベントの発表スライドです。

profile-image

会社勤めのSE・プログラマです。個人としての情報発信も行っており、このアカウントはその用途で使用します。同一ID「suusanex」でGitHub・はてな等でも発信しています。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

WPFに最近の技術を色々取り込んで、見た目 や開発のしやすさを改善しようとしてみる 2024/12/9 須藤(suusanex)

2.

自己紹介  ID:suusanex( connpass・Twitter・GitHub共通)  名前:須藤圭太  サイエンスパーク株式会社という独立系ソフトウェアベンダーに所属  4年ほど受託開発で、上流から下流まで全部を回す  ここ10年ほどは、自社製品開発も担当  Windowsアプリ開発のネタが多い

3.

概要  今年春のBuildでWPFとWin UI 3の併用の方針が出た  最新の体験ならWinUI 3チャレンジ、既存資産を生かすならWPF続投、という感じ  最新の機能や見た目などもどんどんWPFに取り込めるようになっている  が、WPFのプロジェクトテンプレートは未だに真っ白  自力で最新のものを取り込むかどうかで、大違いになってきている  どんなメリットがあって取り込みはどうすればいいかを、紹介します!

4.

紹介する内容  WPFでもWin11っぽいUIを作れるFluentテーマ(要.NET 9)  色々新機能の前提としてGenericHost  WPFでもWindowsAppSDK  WindowsAppSDK アプリライフサイクル   それを使って多重起動時のアクティブ化を実現  アプリライフサイクルとGenericHostは共存OK おまけ コンソールアプリでもGenericHost

5.

WPFでもWin11っぽいUIを作れるFluent テーマ(要.NET 9)  WPFは独自描画なので、OSのUIの変化に追従していない  MahApps.Metro等のライブラリで何とかするか、WinUI 3に行くしか無かった  ついに、容易に使える組み込みのFluentテーマが登場  ダークテーマにも対応  残念ながら.NET 9以降必須だが、使うのは簡単

6.
[beta]
取り込みは簡単


プロジェクトの.NETを9に変更




リソースディクショナリに次の1行を追加




(8以下だとPresentationFramework.Fluentをロードできなくて例外)

<ResourceDictionary
Source="pack://application:,,,/PresentationFramework.Fluent;component/Themes
/Fluent.xaml" />

せっかく配信なので、VisualStudioで動くところを見せます

7.

色々新機能の前提としてGenericHost  最近の新機能を入れようとすると、サンプルで当たり前のように DI(Dependency Injection)が出てきます  しかしWPFのテンプレートは真っ白で、そんな物は影も形もありません  GenericHostを組み込めばその辺も解決できるので、まずそこの話から  GenericHostはDIやLoggerなど開発に便利なインフラが全部入ってる  ある意味デスクトップアプリにおける.NET Aspire  TaskやLINQなどと同じく、使うのが基本であり、使わないのは古くて開発しづ らいコード、になってきている(個人的評価)  オフィシャル情報: https://learn.microsoft.com/jajp/dotnet/core/extensions/generic-host?tabs=appbuilder

8.

GenericHostの組み込み方   1,Template Studio for WPF  テンプレートなので楽だが、Metro等色々入ってるので不要なら手動で消す必要あり  .NET 6で止まっててだいぶコードが古い・・・(Nullableなど未対応)  GenericHostだけではなく、MVVMのCommunity ToolkitやWindowsとPageの Navigataionの仕組みなど色々入っている  特に説明するほどでは無いので、こちらからインストールしてどうぞ  https://marketplace.visualstudio.com/items?itemName=TemplateStudio.TemplateS tudioForWPF 2,手動で組み込み   このセッションではこれをメインに説明します サンプルコード: https://github.com/suusanex/sample_wpf_generichost

9.
[beta]
WPFテンプレートに最小限GenericHost


ざっとポイントを書きますが、せっかく配信なので、VisualStudioで見せます



WPFのテンプレートに、まずGenericHostを追加


<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />



App.xamlのStartupUriは外して、StartupとExit追加、Startupでホスト生成
private IHost _host;
private async void OnStartup(object sender, StartupEventArgs e){
_host = Host.CreateDefaultBuilder(e.Args)
.Build();
await _host.StartAsync(); }



ホストになるクラスを追加。StartAsyncでメインウインドウをShow()




public class ApplicationHostService : IHostedService

DIのところでホストになるクラスを登録
.ConfigureServices(collection => {
collection.AddHostedService<ApplicationHostService>(); })

10.

WPFでもWindowsAppSDK  WinUI 3とセットで登場した、Windows開発をやりやすくするAPI群  そもそもWinUI 3使う機会少なくて長らく謎の存在(個人差があります)  WPFでも使えるようになった!  最新Windowsらしい動きになるちょっとした便利機能も有る   一部採用するだけでもちょっとリッチになる  ちょっとずつでも取り込んでいきたい 必要ランタイムが増えるなど、配布で考えることが増えるのは難点

11.

WPFにWindowsAppSDK組み込み  ざっとポイントを書きますが、せっかく配信なので、VisualStudioで見せます  開発環境にWindows App SDKをインストール Windows App SDK 用の最新のダウ ンロード - Windows apps | Microsoft Learn  NuGetで組み込み・RuntimeIdentifiersを追加  WindowsPackageTypeに値Noneを追加して、普通のWPFの配布方法 (UnPackaged)かつWindows App SDKの初期化を自動で行う  これが最小限。あとは必要な初期化コードを自動生成してくれる <PropertyGroup> <TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> <RuntimeIdentifiers>win-x64</RuntimeIdentifiers> <WindowsPackageType>None</WindowsPackageType> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.240923002" /> </ItemGroup>

12.

WindowsAppSDK アプリライフサイクル  アプリの開始・終了・アクティブ化などを統一的に管理できる仕組み  大きなポイントとして、同一exeから起動される複数のプロセスを「インスタ ンス」として管理できる  例えばこれを利用して、よく要望されるこういう動きを実現できる o o exeは多重起動禁止 o exeを多重起動した場合、すでに起動しているウインドウをアクティブにする 他にも使いどころはありそうだが、ここではその使い方を紹介

13.
[beta]
アプリライフサイクルで多重起動の動作
を実装


ざっとポイントを書きますが、せっかく配信なので、VisualStudioで見せます



アプリのStartupの処理でインスタンスを取得






var instances = AppInstance.GetInstances();

インスタンスの数が1以下だったらインスタンスのActivatedイベントを登録し、そ
こでメインウインドウをActivate


AppInstance.GetCurrent().Activated += OnActivated;



private void OnActivated(object? sender, AppActivationArguments e) {
Current.Dispatcher.Invoke(() => Current.MainWindow?.Activate()); }

インスタンスの数が1を超えていたら、1つ目のインスタンスにリダイレクトして
(Activationを呼び出して)アプリ終了


instances.First() .RedirectActivationToAsync(args);

サンプルコード: https://github.com/suusanex/sample_wpf_winappsdk

14.

アプリライフサイクルとGenericHostは 共存OK  アプリライフサイクルは初期化の流れに手が入るので他との共存が心配になる  GenericHostとの共存も問題なし!  やっていることのレイヤが違うので。  今日出てきたサンプルをくっつけるだけで行けます  くっつけたものをVisualStudioで見せます

15.
[beta]
おまけ コンソールアプリでもGenericHost


WPFの話をしてきましたが、コンソールアプリを作る場合もGenericHostは使
いたい! → 使えます



ざっとポイントを書きますが、せっかく配信なので、VisualStudioで見せます



MainでGenericHostを開始



_ = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<ConsoleHostedService>(); })
.RunConsoleAsync();
IHostApplicationLifetime.ApplicationStartedを登録してそちらで処理

public class ConsoleHostedService(IHostApplicationLifetime _AppLifetime) : IHostedService {
public async Task StartAsync(CancellationToken cancellationToken) {
_AppLifetime.ApplicationStarted.Register(OnStarted);
[STAThread]
private void OnStarted()


サンプルコード: https://github.com/suusanex/sample_console_generic_host

16.

まとめ  WPFの空っぽのテンプレートから、もっと最新技術を使えるように色々盛り込 む方法を紹介しました  皆さん、知らないものはもちろん、知ってても実装方法がピンとこなかったも のも有るのでは?  このセッションの情報でハードルが下がって取り込みができ、開発効率が良く なったら嬉しいです  新しくて便利な物はどんどん取り入れて、効率よく開発して、価値に集中でき るようにしていきましょう!