「既存のWPFアプリをWinUI 3に移したい」——そう考えて手を動かすと、すぐに気づきます。単純にコピペしてもまず動きません。 私も同じ道を通り、名前空間・コントロール・スレッド…と、あちこちで細かく詰まりました。
この記事では、WPFからWinUI 3へ移行するときにどこが変わり、どこでつまずくのかを、一枚のマップとして整理します。細かな書き換え手順よりも、「まず全体像を押さえて心の準備をする」ことを目的にした概要です。WinUIの基礎は入門記事、MVVM周りはMVVM入門も参照してください。
Table of contents
Open Table of contents
大前提:単純移植は向かない
最初に結論から言うと、WPFアプリの「そのまま載せ替え」は基本的に効きません。 名前空間もコントロールも作法も違うため、実態は「移行」というより部分的な作り直しに近くなります。
そのため、既存の安定したWPFアプリを無理に移すより、新規開発でWinUIを選ぶ方が向いています(この判断は入門記事でも触れています)。それでも移行したい場合に、差分の地図を持っておくと迷いが減ります。
1. 名前空間の置き換え
まず大量に出るのが名前空間の違いです。WPFの System.Windows.* は、WinUIでは Microsoft.UI.Xaml.* に変わります。
| WPF | WinUI 3 |
|---|---|
System.Windows | Microsoft.UI.Xaml |
System.Windows.Controls | Microsoft.UI.Xaml.Controls |
System.Windows.Media | Microsoft.UI.Xaml.Media |
using の一括置換である程度は進みますが、クラスによっては移動先が異なるものもあり、機械的な置換だけでは終わりません。
2. コントロールの置き換え
WPFにあってWinUIに「そのままの名前では」存在しないコントロールがあります。代表的な対応は次のとおりです。
| WPF | WinUI 3での代替 |
|---|---|
DataGrid | 標準には無し → ListView で代替。表形式が必要なら Community Toolkit の DataGrid や WinUI.TableView(コミュニティ製)を検討 |
WrapPanel | Community Toolkit の WrapPanel(同名で素直に置き換え可)。大量要素を仮想化したいなら ItemsRepeater + WrapLayout |
TabControl | TabView |
Menu / ToolBar | MenuBar / CommandBar |
「同じ名前がない=作り直し」ではなく、役割の近いモダンなコントロールに置き換えるイメージです。Community Toolkit が代替の受け皿になることも多いです。
3. スレッド:Dispatcher → DispatcherQueue
UIスレッド外から画面を更新する定番の Dispatcher は、WinUIでは DispatcherQueue に変わります。
// WPF
Dispatcher.Invoke(() => { /* UI更新 */ });
// WinUI 3
DispatcherQueue.TryEnqueue(() => { /* UI更新 */ });
非同期処理からUIを触るコードは各所にあるはずなので、ここは確実に書き換えが必要です。
4. リソースとテーマ:DynamicResource → ThemeResource
WPFでテーマ切り替えなどに使った DynamicResource は、WinUIにはありません。 代わりに、テーマ(ライト/ダーク)に追従するリソースは ThemeResource を使います。
<!-- WPF -->
<TextBlock Foreground="{DynamicResource MyBrush}" />
<!-- WinUI 3 -->
<TextBlock Foreground="{ThemeResource MyBrush}" />
固定値でよければ StaticResource はそのまま使えます。テーマ対応が絡む箇所だけ ThemeResource に読み替えるのがポイントです。
5. スタイルのトリガー:Trigger → Behaviors / VisualStateManager
WPFの Style 内の Trigger(DataTrigger / MultiTrigger など、状態に応じた見た目の切り替え)は、WinUIにはありません。置き換え先は、用途によって2つに分かれます。
- データや条件による切り替え → Behaviors(Community Toolkit の XAML Behaviors)。
DataTriggerBehaviorやEventTriggerBehaviorを使います。インライントリガーより再利用・テストがしやすいのが利点です。 - コントロールの視覚状態(押下・ホバー・無効など) →
VisualStateManager(ビジュアルステート)。
いずれも「トリガーをそのまま移す」のではなく、考え方から組み替える箇所です。
6. バインディング:Binding → x:Bind
WPFの {Binding}(DataContext 起点・実行時解決)に対し、WinUIでは型安全で高速な {x:Bind}(ページの分離コード起点・コンパイル時解決) が推奨です。既定モードも OneWay → OneTime と変わります。
この差分はMVVMの組み方に直結するため、詳しくはMVVM入門記事の「WPFのMVVMとの違い」で解説しています。従来型の {Binding} もWinUIで使えますが、移行を機に x:Bind へ寄せるのがおすすめです。
7. 画像:BitmapImage の名前空間が変わる
WPFで画面表示に使う BitmapImage は System.Windows.Media.Imaging にありますが、WinUIでは Microsoft.UI.Xaml.Media.Imaging.BitmapImage に変わります。多くの場合、移行はまずこの名前空間の読み替えが中心です。
加えて、System.Drawing.Bitmap などGDI+系のAPI(どちらかというとWinForms寄り)を画像処理で使っていた場合は、XAML表示とは相性が悪いため、そこも見直しが必要になります。
まとめ
WPFからWinUI 3への移行は、「差分を知っていれば怖くないが、知らないと各所で足を止められる」作業です。主なマップは次のとおり。
- 名前空間 …
System.Windows→Microsoft.UI.Xaml - コントロール …
DataGrid/WrapPanel/TabControlなどを近いものに置換 - スレッド …
Dispatcher→DispatcherQueue - リソース/テーマ …
DynamicResource→ThemeResource - トリガー …
Trigger→ Behaviors(Community Toolkit)/VisualStateManager - バインディング …
{Binding}→{x:Bind} - 画像 …
BitmapImageの名前空間変更(System.Windows.Media.Imaging→Microsoft.UI.Xaml.Media.Imaging)
繰り返しになりますが、実態は部分的な作り直しです。小さな画面から一つずつ置き換え、都度動かして確認していくのが、遠回りに見えて一番の近道でした。
