MainWindow静的 HTML によるヘルプ作成をアシストするツール「ちょちょいとファイル合併 2」(ソースコード)を WinUI 3(Windows App SDK)で作成した。

実際にアプリを作ると WinUI 3 の良いところ悪いところを実感できたので、そのまとめ。

なお、開発は Template Studio for WinUI を用いて行っているので、素の WinUI 3 より少し高機能な環境を使用している。

良いところ(メリット)

【デザインはわりと好き】

settingsボタンやチェックボックスなどのデザイン(Fluent Design)はわりと好き。

少なくとも、素の WinForms や WPF よりは洗練されている感がある。

マテリアルデザインはデフォルト(?)の紫をはじめとしたどぎつい色が多いので、それよりも落ち着いていて好き。ただ、パステル調のマテリアルデザインはきれいなので、そちらのほうが好き。

あと、ウィンドウを半透明+ぼかしにするアクリル効果は使いどころが難しいと思う。

【アクセスキーが表示されるのが良い】

AccessKeyコントロールにアクセスキー(Alt+x)が設定されている場合、Alt キーを押して離すとアクセスキーが表示されるのは分かりやすい。

普通のボタンはラベルにアクセスキーを表示しておけるが、アイコンボタンはアクセスキーを表示できないので、アクセスキー表示機能があることでユーザーはアクセスキーを認識できる。

Alt キーを「離した」時に表示されるので、既に知っているアクセスキーを使うときはわざわざ表示されず、うざくないのもポイント。

【RelativePanel】

WPF にあった DockPanel はなくなり、代わりに RelativePanel が登場。ちょっと使い方が難しいが、その分、高機能になっている。

RelativePanel で一番気に入ったのは、DockPanel の LastChildFill をより良く実現できること。

MainWindowDockPanel.LastChildFill の場合、残りのスペースを埋めるコントロール(右の図ではメイクファイル入力欄)を XAML 上で最後に記述することになり、結果的に、タブオーダーが見た目と異なってしまう(参照ボタンの後に入力欄が来る)。

RelativePanel なら、残りのスペースを埋めるコントロールを好きな順番で書くことができる(RelativePanel.RightOf / LeftOf を両方指定すると伸びる)ので、タブオーダーが見た目通りになる。

【静的バインディング】

XAML でのバインディングに静的バインディングの {x:Bind} が使える。

WPF は動的バインディングの {Binding} だったので、実行してみないとエラーが分からず、この点が個人的にとても嫌いだった。WinUI 3 で静的バインディングになり、コンパイル時に解決するのでミスが減る。パフォーマンスも向上するようだ。

ただ、デフォルトでバインディングの Mode が OneTime になっているので、WPF に慣れていると「値反映されない?」ってことになりがちなのは注意。

なお、{Binding} も使える。

【マルチリンガル】

恐らく Template Studio のおかげかと思うが、ローカライズの仕組みが最初から使える状態になっているのは良いと思う。

Ver 1.83 現在ではちょちょいとファイル合併 2 は多言語対応していないが、実験用に多言語対応してみてもいいかもしれない。

悪いところ(デメリット)

正直、悪いところが多すぎるし、1 つ 1 つのダメージがでかすぎる。なんとなくの印象だけど、すぐには改善されない気がする……。

※自分が気付いてないだけかもしれないので、もしご存じのかたはコメントいただけると幸いです。

【ウィンドウの機能が弱すぎる】

なんと、ウィンドウに Left / Top プロパティーがない。Template Studio では素の Window よりも強いサードパーティーの WindowEx を使っているが、それでもない。ウインドウを動かすには、コードビハインドで AppWindow.Move() を使う。MVVM どこ行った……。

ウィンドウサイズをコンテンツに合わせて調整する SizeToContent プロパティーもない。これを自力で実現するために無駄にコードを書く必要がある。自分は何をやっているのか……と虚しくなる。

なお、メインウィンドウに限っては XAML で Width / Height プロパティーを指定しても効かないが、これは Template Studio が何かしているからのようだ。コードビハインドで指定すると効くし、子ウィンドウなら XAML でも効く。

【ウィンドウをモーダルにできない】

子ウィンドウをモーダルウィンドウ(閉じるまで親ウィンドウを操作できないウィンドウ)にできない。モードレスになるので、環境設定ウィンドウで環境設定している時にメインウィンドウをクリックすると、メインウィンドウの操作ができてしまう。

確かに Windows 以外の OS に目を向ければ Haiku OS の流儀はすべてモードレスで、OS 全体でその流儀が浸透しているなら、モードレスはモードレスで使い勝手が良いし、個人的な好みで言えばモードレスかもしれない。しかし、Windows の流儀はモーダルなので、自分のアプリだけモードレスというのは違和感しかない。

ちょちょいとファイル合併 2 では擬似的にモーダルになるようにまたしても無駄にコードを書くこととなり、むなしさが増した。

PaintWindows 11 付属のペイントは WinUI 3 でありながら本物のモーダルウィンドウを実現しているっぽくて、どうやっているのか気になる。

【メッセージボックスが見切れる】

ContentDialogWinUI 3 のメッセージボックスは ContentDialog だが、メインウィンドウの範囲内でしか表示できないので、メインウィンドウよりも大きな内容を表示しようとすると見切れてしまう。

MessageDialog仕方ないので MessageDialog を使っているが、デザインが WinUI 3 とは異なるので違和感が出てしまう。

【ポップアップメニューがきつきつ】

Kitsu本質的には ContentDialog と同じ問題なのではと思うが、ポップアップメニュー(Flyout)も無理矢理メインウィンドウの範囲内で表示しようとするので、アイテム数が多いとスクロールバー表示になってしまい、非常に使いづらい。

Item3対処方法としては、スクロールしなくてもメインウィンドウ内に納まるアイテム数にするしかない。

ボタンとの位置関係によっては、納まるアイテム数にしていても、初回だけはスクロールバー表示になってしまい、これはバグだと思う。

ドキュメントによれば、FlyoutBase.ShouldConstrainToRootBounds プロパティを false にすればウィンドウ外に表示できるようなのだが、なぜか効かない。Popup.ShouldConstrainToRootBounds プロパティのドキュメントには「WinUI 3 では false はサポートされない」と書いてあるので、そういうことなのかもしれない。

【パッケージを作るの面倒】

公開用のパッケージを作る際、msix が作成され、msixbundle が作成されない。

手動で msixbundle を作成するのが面倒くさい。

【ロードマップが更新されない】

Windows App SDK のロードマップはこのへんこのへんに書かれているが、1.1 あたりで止まっている。

既に 1.2 が出ているが、この先どうなるのかの見通しが分からない。

【バグっぽい】

集約エラーハンドラー(Application.UnhandledException)がうまく動かなくてずっと悩んでいたが Windows App SDK 1.2 になったら動いたので、ただのバグだったようだ。

ポップアップメニューの初回位置もしかり。

【情報が少ない】

ノウハウしかり、ロードマップしかり、WinUI 3 に関する情報が非常に少ない。

クラスの検索をすると WinUI 3 ではなく UWP が引っかかりがち。

Uwp例えば、現時点では「TextBlock WinUI3」で検索すると UWP の TextBlock(Windows.UI.Xaml.Controls 名前空間)がトップに出てきて、WinUI 3 の TextBlock(Microsoft.UI.Xaml.Controls 名前空間)にはたどり着けない。

総評

良いところに目を向けて活用していきたいと思うものの、少なくとも現状では、WinUI 3 での開発は茨の道だと思う。

機能比較表

WPF と WinUI 3 の機能比較表を作成

更新履歴

  • 2022/11/23 初版。
  • 2022/11/26 バインディングについて追記。
  • 2022/11/26 ポップアップメニューについて追記。
  • 2023/05/21 機能比較表について記載。