.NET MAUI(.NET 9 / MAUI 9)に更新したら、以前は移行時に追加していた「Microsoft.Maui.Controls.Compatibility」を参照しなくてもビルドできる――そんな状況が増えています。この記事では、なぜ不要になったように見えるのか、そして“まだ必要になる条件”を、実務で迷わない判断手順と置き換え方まで含めて整理します。
結論:参照が不要になったのは「互換レイヤーが“標準装備の前提”ではなくなった」から
まず結論から言うと、Microsoft.Maui.Controls.Compatibility は、Xamarin.Forms → .NET MAUI への移行を助けるための互換(Compatibility)レイヤーです。したがって、アプリ内に Xamarin.Forms 由来の互換依存(特に旧Renderer系など)が残っていなければ、参照は不要になります。
そして .NET MAUI 9(.NET 9)では、アップグレードの手順として「アプリが互換パッケージ内の型を使っていないなら、Microsoft.Maui.Controls.Compatibility の PackageReference を外す」ことが明確に案内されています。つまり「必要な人だけ追加する」立ち位置がより強くなりました。
加えて、.NET MAUI のテンプレート側も「最初から互換を抱え込む」運用から切り離されてきています。MAUI のメンテナが、テンプレートに入っていた互換参照は“移行の波”が落ち着いたら分離して外す(.NET 9での作業になりそう)という趣旨の説明をしています。
| 状況 | Microsoft.Maui.Controls.Compatibility の参照 | おすすめ対応 |
|---|---|---|
| 純粋なMAUI(Handlers中心)、互換型を使っていない | 不要になりやすい | 参照を外してOK(ビルドで確認) |
| RelativeLayoutなど“Compatibility名前空間”のUIを使っている | 必ずしも必要とは限らない(後述の注意点あり) | 警告(Obsolete)を見て、Grid等へ置換計画 |
| Xamarin.FormsのカスタムRendererや互換初期化が残っている | 必要になる可能性が高い | 短期は維持、最終的にHandlerへ移行 |
| 古いサードパーティが互換依存している | 必要になることがある | ライブラリ更新・置換、依存の棚卸し |
まず押さえるべき前提:「Compatibility 名前空間」と「Compatibility パッケージ」は混同されがち
“参照しなくてよくなった”話をややこしくしているのが、「Microsoft.Maui.Controls.Compatibility」という文字列が、名前空間(namespace)としても、NuGetパッケージ名としても存在する点です。
実務では次の2つを分けて考えるとスッキリします。
| 区分 | 例 | どこに入っているか(目安) | 重要ポイント |
|---|---|---|---|
| Compatibility 名前空間の型 | RelativeLayout / Constraint など | Microsoft.Maui.Controls.dll 側に含まれる型もある | パッケージ参照を外しても使えてしまうケースがある(=完全移行とは限らない) |
| Compatibility NuGetパッケージの型 | UseMauiCompatibility / RendererToHandlerShim など | Microsoft.Maui.Controls.Compatibility.dll(互換パッケージ) | 旧Renderer系の互換・移行補助が中心。しかも“deprecated(将来削除予定)”が増えている |
たとえば RelativeLayout は「Microsoft.Maui.Controls.Compatibility 名前空間」ですが、ドキュメント上は assembly が Microsoft.Maui.Controls.dll になっているため、互換NuGetパッケージ参照を外しても、RelativeLayout だけは残って見えることがあります。これが「参照不要になったように見える」典型パターンです。
しかしその一方で、RendererToHandlerShim や UseMauiCompatibility のように、互換パッケージ(Microsoft.Maui.Controls.Compatibility.dll)に属する型もあります。こちらを使っている場合は、参照を外すと当然ビルドが落ちます(そしてこれらは deprecated と明記されています)。
.NET MAUI 9で「外してよい」に寄ってきた技術的な背景
“互換を最初から入れる”運用が必須でなくなってきた理由は、単に「移行が進んだから」だけではありません。技術的にも、互換レイヤーは次の点で常時同梱する価値が下がりやすいからです。
- 互換機能はdeprecated(将来削除)へ進んでいる
たとえば .NET MAUI 9 では、Compatibility 名前空間のレイアウト群が obsolete(非推奨)扱いになっています。テンプレートが標準で抱え込むより、「必要な人が必要な期間だけ」使う方が健全です。 - UseMauiCompatibility 自体が deprecated で、不要なら外せと明確に言っている
UseMauiCompatibility のAPI説明には、互換機能は deprecated で将来削除されること、また使っていないなら参照や呼び出しを外さないと“不要なオーバーヘッドで性能に悪影響”がある旨が記載されています。 - テンプレートに入れていた理由が「常に必要」ではなかった
MAUI側の説明では、テンプレートの PackageReference は「ワークロードに含まれるものではなく、NuGetでバージョンを指定したい」などの事情もあって置かれていた、という文脈があります。移行の波が落ち着けばテンプレートから外す方向(.NET 9タスク)とも述べられています。
最短で判断する:Compatibility 参照が必要かどうかのチェック手順
手順1:csprojから PackageReference を外して“まずビルド”
最も速く確実なのは、実際に参照を外してビルドし、エラーが出るかで判断することです(移行フェーズなら、エラーが出ること自体が「互換依存の残骸リスト」になります)。
典型的には、過去の移行手順で次のように追加していることがあります。
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
.NET MAUI 9 へのアップグレード文脈では、互換パッケージの型を使っていないなら、この参照を外すことが推奨されています。
手順2:コード全体を「文字列検索」で棚卸しする
ビルド前に、Visual Studio / Rider / VS Code で全検索しておくと修正の見積もりが立ちます。以下を検索してください。
- Microsoft.Maui.Controls.Compatibility
- UseMauiCompatibility
- ExportRenderer(Xamarin.FormsのRenderer系が残っているサイン)
- RelativeLayout / Constraint(互換レイアウトの可能性)
- RendererToHandlerShim
UseMauiCompatibility が残っているなら、互換レイヤー依存の可能性が高いです。しかもこの呼び出し自体が deprecated で、不要なら外すように明言されています。
手順3:参照を外したあと、出てきたエラーを「分類」して潰す
ビルドエラーの原因は大きく3系統に分かれます。どの系統かを見極めると、直し方が決まります。
| 分類 | よくある症状 | 根本原因 | 王道の解決 |
|---|---|---|---|
| 互換パッケージの型を直接使っている | UseMauiCompatibility / RendererToHandlerShim などが見つからない | 互換NuGetに依存 | Handlerへ移行(または短期的に参照を残す) |
| 互換レイアウト(RelativeLayout等)を使っている | Obsolete警告が増える/将来リスク | Compatibility名前空間のレイアウト | Grid/AbsoluteLayout等へ置換計画 |
| サードパーティ起因 | 自分のコードにないのに互換DLLが必要と言われる | 依存ライブラリが互換を要求 | ライブラリ更新・置換、依存関係の整理 |
「まだ必要になり得る」代表例:RelativeLayout(互換レイアウト)が残っている
移行プロジェクトで特に残りやすいのが RelativeLayout です。.NET MAUI では RelativeLayout の利用は推奨されず、可能なら Grid を使うよう案内されています。また「どうしても必要なら Compatibility 名前空間にある」という扱いです。
実際に XAML では次のように、Compatibility 名前空間の xmlns を追加して使う例が示されています。
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:compat="clr-namespace:Microsoft.Maui.Controls.Compatibility;assembly=Microsoft.Maui.Controls">
<compat:RelativeLayout>
<!-- ... -->
</compat:RelativeLayout>
</ContentPage>
ここで重要なのは、RelativeLayout は“動くからOK”ではなく、互換レイアウトとして残されているだけという点です。さらに .NET MAUI 9 では Compatibility 名前空間のレイアウト群は obsolete 扱いになっています。つまり今は動いても、将来の更新で置換を迫られる可能性が高い領域です。
RelativeLayout → Grid 置換の現場メモ
RelativeLayout は「相対配置」「割合(Factor)」「View間の依存」を書きやすい反面、レイアウトの計測・配置が複雑になりがちです。置換時は“完全一致”にこだわりすぎず、まずは以下の型に当てはめると短期間で移行できます。
| RelativeLayoutでやっていたこと | Gridでの置き換え方針 | 実装のコツ |
|---|---|---|
| 縦に「上:自動 / 下:残り全部」 | RowDefinitions=”Auto,*” | “AndExpand”の代替にもなりやすい |
| 横に「左:固定 / 右:残り全部」 | ColumnDefinitions=”固定,*” | 固定は数値、残りは* |
| Viewを重ねる(Z方向の重なり) | Gridで同一セルに複数配置 | ZIndexや配置順で調整 |
| 親サイズの割合で幅を決める | Gridの*配分、またはAbsoluteLayout | “80%”は ColumnDefinitions=”8*,2*” の発想が使える |
「まだ必要になり得る」代表例:Xamarin.FormsのカスタムRenderer依存が残っている
Xamarin.Forms 時代の資産で多いのがカスタムRendererです。.NET MAUI ではRendererの代わりに Handlers という仕組みが導入され、Rendererよりパフォーマンス面で利点があることが説明されています。
ただし移行現場では「全部を一気にHandlerへ」は難しいことが多いので、選択肢は現実的に次の2つになります。
- 短期(延命):既存Rendererを再利用する(shimの範囲で)
.NET MAUI は一部のRendererについて“shimmed renderers”として再利用を支援しており、対象となる基底クラスの例も挙げられています。 - 中長期(推奨):Handlerへ移行する
RendererからHandlerへ移行する手順が公式に整理されており、プロパティ変更の扱いなども含めて移行ガイドがあります。
ここで、互換パッケージ参照が問題になるのは「旧Renderer互換を有効化するために UseMauiCompatibility を呼んでいる」ケースです。UseMauiCompatibility は deprecated で、不要なら呼び出しも参照も外すよう明記されています。つまり残すなら“期限付きの暫定”として扱うのが安全です。
UseMauiCompatibility が残っているかの確認例
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
// .UseMauiCompatibility(); // ← 残っていたら互換依存の可能性が高い
return builder.Build();
}
}
「まだ必要になり得る」代表例:サードパーティが互換依存している
自分のコードからは互換依存が見当たらないのに、ビルドや実行時に互換DLLが必要と言われる場合、サードパーティが原因のことがあります。特に移行初期に導入したライブラリ(古いUI、古い拡張、移行用Compat系)は要注意です。
この場合の鉄板の進め方は次の通りです。
- まずアップデート可能なライブラリは最新へ
互換依存が外れているケースもあります(ベンダー側で段階的に整理されるため)。 - 依存関係を可視化する
「どのパッケージが Compatibility に引っ張られているか」を確認し、更新か置換かを判断します。 - 互換が必要な間は“使う理由”を残す
「なぜ残しているか」が分からない参照は、数か月後に技術負債になります。
“外してよい”の判断がついたら:メリットを最大化するための運用ポイント
Compatibility参照を外すのは、単なる「依存が1つ減る」以上の価値があります。特にチーム運用では次の効果が出やすいです。
- 非推奨APIの警告を減らし、将来の破壊的変更に備えやすい(Compatibilityレイアウトは obsolete になっています)
- 不要なオーバーヘッドを避けやすい(UseMauiCompatibilityは“不要なら外せ”とされます)
- 移行の残骸が可視化される
外して壊れる箇所=移行が終わっていない箇所、というシンプルな構図になります。
| チームで決めておくと効くルール | 理由 | おすすめの落としどころ |
|---|---|---|
| 新規画面はCompatibilityレイアウト禁止 | obsolete領域を増やさない | Grid/VerticalStackLayout/AbsoluteLayoutで設計 |
| UseMauiCompatibility は原則禁止(例外は期限付き) | deprecatedで将来削除予定 | 例外時は「撤去予定日」「担当」を記録 |
| Renderer資産は“最小限の延命→Handler移行”で段階実行 | 全置換は重いが、放置も危険 | 機能単位でHandler化のバックログ化 |
まとめ:Compatibility参照は「必要な時だけ」—外して壊れる箇所が移行の地図になる
Microsoft.Maui.Controls.Compatibility の PackageReference を入れなくても動くように見えるのは、互換レイヤーが“常時前提”から外れ、アプリが互換パッケージの型を使っていないなら外してよいという案内が明確になったことが大きいです。
ただし、参照を外せたからといって「互換要素がゼロ」とは限りません。RelativeLayout のように Compatibility 名前空間の型が別のアセンブリ側に残っていることもあります。“参照が不要”と“互換依存がない”は別物として扱い、外した上でエラーや警告を手がかりに、HandlersやGridへ段階的に寄せていくのが最短ルートです。

コメント