前回、Mauiの基本紹介を行いました。理論的には、今回最初のMauiアプリケーションを作成し、詳細な評価を行い、徐々に深く掘り下げる予定でした。
もしMauiの初めてのアプリケーションを作成したい場合は、.NET MAUI でモバイルアプリを作成 — はじめに および MAUI と Blazor でUIを共有、Flutterに匹敵、Windows、macOS、Android、iOS、Web 共通UIを実現 を参照してください。この記事の重点はMauiアプリケーションの作成ではなく、Mauiプロジェクトのより良い設定方法です。
煩わしい "obj" を解決する
長い間、私たちを悩ませてきた問題があります。C# プログラムをコンパイルするたびに、プロジェクトフォルダーに "obj" ディレクトリが生成され、目障りです。git にコミットするたびに、一つずつ除外する必要があります(プロジェクトが多いと地獄です)。これは非常に煩わしいです。では、それを別の場所に移動できないでしょうか?
以下の設定を行う前に、次の手順を実行してください。
- C++ プロジェクトを作成します(C++ プログラム開発をするためではなく、今後の学習に非常に役立ちます)

XML ファイルを作成し、Directory.build.props にリネームします(名前は自由ですが、私はこの名前が好きです)



Directory.build.props をダブルクリックして開き、XML の内容をすべて削除し、次の設定を追加します。
<Project>
<PropertyGroup>
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>
ここでは BaseIntermediateOutputPath 設定フィールドの意図については説明しません。知りたい場合は、一般的な MSBuild プロジェクト プロパティ - MSBuild | Microsoft Docs を参照してください(VS2022 for Mac を使用している場合、このプロパティはサポートされていないことに注意してください。このバグは VS2019 for Mac から存在し、Microsoft は無視しているようです)。そのため、厄介な事態を避けるために、条件判定を追加する必要があります。その条件は、オペレーティングシステムが Windows の場合にのみ、この設定が有効になるというものです。
<!-- このプロパティを使うと obj にさようならできます -->
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
ここで言及しておきたいのは、Microsoft VS チームは本当に強力だということです。VS をインストールするだけで、異なるプラットフォームで同じコードを開くことができ、特別なコンパイル設定は必要ありません。
私たちは家族です
ソリューションに複数のプロジェクト(csproj)が存在する場合、すべてのプロジェクトの dll や exe、設定ファイルが一箇所にコンパイル・生成されることを望むでしょう。通常、手動でコンパイル生成パスを設定しますが、この方法は推奨されません。なぜなら、選択するパスは常に信頼できないからです(特にチームプロジェクトの場合)。次のように少し変更するだけで済みます(この設定も Directory.build.props に追加します)。
<PropertyGroup>
<!-- このプロパティを使うと統一された生成パスを設定できます -->
<OutputPath>$(MSBuildThisFileDirectory)Binary\</OutputPath>
</PropertyGroup>
全部に適用する
よくこう考えることがあります。「一箇所で設定すれば、すべてのプロジェクトに変更が反映されるようにできないか?」たとえば、Nullable の有効化や C# の言語バージョンなどです。その場合は、Directory.build.props に以下の設定を追加するだけです。
<PropertyGroup>
<!-- このプロパティを使うと統一された生成パスを設定できます -->
<OutputPath>$(MSBuildThisFileDirectory)Binary\</OutputPath>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
君がいなきゃダメだ
ソリューション内のすべてのプロジェクト(csproj)が同じパッケージを必要とする場合、パッケージの参照を一度だけ行うことはできないでしょうか?それでは、一緒に操作してみましょう。
- XML ファイルを作成し(もうおなじみですね)、
Directory.build.targetsにリネームします(私はこの名前が好きです)


Directory.build.targetsの内容を次のように変更します。
<Project>
<!-- この設計により、現在のソリューション内のすべてのプロジェクトがパッケージを取得できます -->
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
能動的にさせる
上記の設定を完了すると、あなたはソリューション管理の達人になりました。しかし、まだ十分ではありません。.NET6 や C#10 ではファイルスコープの名前空間(File-scoped)が導入されました。namespace xxx; と書くだけで、不要な中括弧が減り、コードがよりすっきりします。残念ながら、何も変更しなければ、それは決して能動的にはなりません。作成するデフォルトのクラスは常に次のようになります。
namespace MauiLib1
{
internal class Class2
{
}
}
以下の操作を行うと、より言うことを聞くようになります。
- editorconfig を作成します


.editorconfigをダブルクリックし、File scoped を有効にします(もし設定画面ではなく直接テキストが開かれた場合でも心配しないでください。次回の再起動後に設定を完了すれば大丈夫です)

これで、いくつかの効率的な設定が完了しました。VS を閉じて、ソリューションを再度開くと、上記のすべての設定が有効になります。すでに生成されたコンパイルゴミ(以下のようなもの)は忘れずに削除してください。

この時点で、新しいクラスを作成すると、次のようになります。
namespace MauiLib1;
internal class Class3
{
}
ソリューションを再コンパイルすると、すべての dll と exe が Binary フォルダー以下に生成されます。各 csproj ディレクトリは非常にきれいになります(注意:上記の設定は C++ プロジェクトには無効です。C++ プロジェクトは個別に設定する必要がありますが、ここでは説明しません)。
彼を忘れないで
上記の設定を完了しましたが、先ほど作成した C++ プロジェクトは何の役にも立っていないようです。そう、C++ プロジェクトはあなたに見せるだけのものです(私はあなたをからかっているだけです)。次に検討する必要があるのは、これらをどうやって知ったのかということです(図参照)

実際、これらは VS の組み込みマクロ定義の一部です。C# ではなぜこれらのマクロがあるのかを知ることはできません。そのため、C++ プロジェクトを使用する必要があります。




ここで、これらの様々な設定フィールドと、対応するマクロが表示する値を確認できます。このマクロは VS のものなので、C# プロジェクトでも有効です。
与えすぎだ
次に、Maui の深層設定について検討します。Windows 上では、デフォルトで Android、iOS、Mac Catalyst がコンパイルされます。多すぎて、まったく必要ない場合は、TargetFrameworks を変更できます(例えばこう)

注意:この項目を変更すると、他のプラットフォームを選択してコードが正しいかどうかを確認できなくなります(コードの信頼性が保証されなくなります)。他のプラットフォームのコンパイル設定を削除すると、最も明白な効果はコンパイルが異常に速くなることです。
彼女を忠実にする
Windows アプリケーションを生成するとき、Windows プラットフォームに関連するパッケージを参照したい場合があります。たとえば、よく知られている Pinvoke.User32 などです。明らかに、このライブラリは Windows プラットフォームにのみ適しています。他のプラットフォームで参照してもコンパイルエラーにはなりませんが、パッケージファイル内にこの無関係な dll が含まれることになります(たぶん、テストしていませんが、推測です)。これは避けたいので、次のようにします。
<!-- Windows 専用の設定。Windows の忠実なパートナーにします -->
<ItemGroup Condition="$(TargetFramework.Contains('-windows'))">
<!-- Required - WinUI does not yet have buildTransitive for everything -->
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
</ItemGroup>
彼らを隔離する必要がある
コードを書いているとき、Windows には適用できるが他のプラットフォームには適用できないコード部分が出てくることがよくあります。その場合は、コンパイルマクロ #if #elif #else #endif などを使うことができます。
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if WINDOWS
string? name = "Windows";
#elif MACCATALYST
string? name = "Mac";
#else
string? name = "Mobile";
#endif
return builder.Build();
}
自分自身を取り戻させる
Maui で作成した Windows アプリケーションが exe をダブルクリックするだけで直接実行できることを期待しています(これは以前は夢でした)。今では、2つの設定を変更するだけで実現できます(メインプログラムのプロジェクトファイル csproj に以下を追加します。この設定を使用すると、anycpu コンパイルがサポートされなくなるため、条件付きコンパイルを行います)。
<!-- この方法により、Maui で Windows 上で生成された exe が自分自身を取り戻せます -->
<PropertyGroup Condition="'$(Platform)' != 'AnyCPU' And $(TargetFramework.Contains('-windows'))">
<!-- Unpack : SelfContainedDeployment for winui3 -->
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
</PropertyGroup>
マルチコンパイルプラットフォームの設定
前の変更では、exe の直接実行を実現するために、anycpu コンパイル環境では完全にサポートされない設定を追加しました。そのため、マルチプラットフォームコンパイルスキーム(x64、x86、ARM64 など)を設定する必要があります。設定方法は次のとおりです。
- 構成マネージャーを開きます

- X64 などのプラットフォームコンパイルを追加します


以上で、ソリューションおよびプロジェクト(csproj)のほとんどの設定を完了しました。これらの設定を行うことで、作業の一部が非常にスムーズになります。
上記の設定はすべて github にアップロードされています。