上一篇我們做了 maui 的基本居間,理論上這一篇應該會創建第一個 maui 的應用,以便對此進行詳細的評估,並逐步深入。
如果你需要进行 Maui 首个应用的创建,那么欢迎访问.NET MAUI 创建移动应用—Get Start,以及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,那么很抱歉的告诉你他不支持这个属性,我在官方的 issue 翻阅过这个 bug 早在 vs2019 for mac 就存在,只不过微软视而不见),所以为了避免尴尬的事情发生,我们需要加上一个条件判定,这个条件就是当操作系统是 windows 时这个设置项才生效
<!--这个属性可以让你跟obj say goodbye-->
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
在這裡我不得不說微軟 vs 團隊是真的強大,你只需要安裝 vs 就能在不同的平台打開同一份代碼,而不需要做其他的編譯設置
我們是一家人
当一个解决方案(Solution)存在多个项目时(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>
不能沒有你
你是否有這樣的困惑,當我的解決方案(solution)下的所有項目(csproj)都需要用到同一個 package 時,我能否只要做一次包的引用行為?接下來請跟我一起操作:
- 创建一个 xml(这已经很熟悉了),将他改名为
Directory.build.targets(我喜欢这个名字)


- 将
Directory.build.targets中的内容修改为:
<Project>
<!--这样的设计可以让你当前解决方案下的所有项目都能获取到package-->
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>
</Project>
讓他變得主動
完成上述設置你已經成為一個解決方案管理高手了,但是這還不夠,我們都知道.net6 或者是 c#10 引入了文件級別的命名空間(file-scoped)你只需要寫一個 namespace xxx,更少的大括號讓你的代碼看起來更加簡潔,很可惜如果你不做任何改變,那麼他永遠不會那麼主動,你創建的默認 class 他一定長這樣:
namespace MauiLib1
{
internal class Class2
{
}
}
請跟我完成以下操作,他會變得更聽話:
- 創建一個 editorconfig


- 雙擊.editorconfig,開啟 file scped 配置(如果你打開的不是設置界面而是直接打開的文本,請不用擔心,在下一次重啟後再完成後續的設置即可)

至此你就完成了部分高效設置,關閉 vs,重新打開解決方案,上述所有設置才會生效,別忘了刪除已經產生的編譯垃圾,如以下這些:

此時你創建的新的 class,他變成了這樣:
namespace MauiLib1;
internal class Class3
{
}
重新編譯解決方案,你的所有 dll 和 exe 都已經生成到 binary 下面了,每一個 csproj 目錄下都相當乾淨了(注意以上設置對 c工程無效,c工程需要單獨配置,這裡不做居間。
別忘了他
完成上述設置,我們剛剛創建的 c工程似乎都沒有起到任何作用,沒錯 c工程只是給你看看的(我就是玩兒你),接下來我們需要探討的是,這些你是怎麼知道的(如圖)

其實這些是 vs 的一些內置宏定義,我們在 c#中無法得知為什麼有這些宏,此時我們需要用到 c++項目




在這裡你可以看到這些形形色色的設置欄位以及對應宏所顯示的值了,這個宏是屬於 vs 的,所以 c#工程也有效
給得實在太多了
接下來我們會進行一些 maui 的深層設置探討,在 windows 上,總是默認給我編譯出 android 、ios、maccatalyst,太多了我根本不需要,那麼可以修改 targetframeworks(比如像這樣)

注意:一旦修改了這項,也就意味著你再也不能夠選擇其他平台查看代碼是否正確(代碼可靠性將得不到保證)(去掉其他平台編譯設置最直觀的表象就是編譯變得異常的快)
讓她變得忠誠
當我生成 window 的應用時,我們要引用一個 window 平台相關的 package,比如我們很熟悉的 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 就能夠直接運行(這在以前是個奢望),現在你只需要修改兩項設置就可以做到(在主程式的工程文件 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 等),配置方法如下:
- 點開 configuration manager

- 新增 x64 等平台編譯


綜上,我們完成了解決方案(solution)以及項目(csproj)中的絕大多數設置,做好這些設置會讓你一部分工作變得得心應手。
以上设置都已上传github