通过将多项目应用升级到多项目 Xamarin.Forms .NET 多平台应用 UI(.NET MAUI)应用,可以通过创建新的多项目 .NET MAUI 应用,然后将代码和资源从 Xamarin.Forms 应用迁移到多项目 .NET MAUI 应用来实现。 然后,还需要执行其他步骤来利用 .NET MAUI 中的更改。
若要手动将多项目应用迁移到多项目 Xamarin.Forms .NET MAUI 库应用,必须:
- 请将您的 Xamarin.Forms 应用更新为使用 Xamarin.Forms 版本 5。
- 将应用的依赖项更新到最新版本。
- 确保应用仍然有效。
- 更新命名空间。
- 解决任何 API 更改。
- 使用 .NET 8 版本升级或替换不兼容的依赖项。
- 编译并测试应用。
为了简化升级过程,应创建与应用 Xamarin.Forms 同名的新多项目 .NET MAUI 应用,然后在代码、配置和资源中复制。 这是下面概述的方法。
更新您的Xamarin.Forms应用
在将您的 Xamarin.Forms 应用升级到 .NET MAUI 之前,您应先将您的 Xamarin.Forms 应用升级以使用 Xamarin.Forms 5,并确保它仍然能够正常运行。 此外,你应该将你的应用程序使用的依赖项更新到最新版本。
这将有助于简化迁移过程的其余部分,因为它将最大程度地减少 Xamarin.Forms 与 .NET MAUI 之间的 API 差异,并确保在可行的情况下使用与 .NET 兼容的依赖项版本。
创建新项目
在 Visual Studio 中,创建与项目同名 Xamarin.Forms 的新 .NET MAUI 多项目应用。 多项目模板为 Android、iOS、Mac Catalyst 和 WinUI 提供了一个适用于 Android、iOS、Mac Catalyst 和 WinUI 的 .NET MAUI 应用,其中包含多个独立的应用项目。
注释
可以删除不支持的平台的应用项目。
打开类库的项目文件将确认你有一个 .NET SDK 样式的项目:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFramework>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<UseMaui>true</UseMaui>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
打开特定平台项目时,还应确认你已设置类似的属性集,包括版本控制和对库项目的引用。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21.0</SupportedOSPlatformVersion>
<OutputType>Exe</OutputType>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseMaui>true</UseMaui>
</PropertyGroup>
<!--
...
-->
<ItemGroup>
<ProjectReference Include="..\MauiApp.1\MauiApp.1.csproj" />
</ItemGroup>
</Project>
将文件复制到 .NET MAUI 应用
库项目中的所有跨平台代码 Xamarin.Forms 都应复制到 .NET MAUI 库项目的同名文件夹和文件中。
自定义呈现器可以在 .NET MAUI 应用中重复使用,也可以迁移到 .NET MAUI 处理程序。 有关详细信息,请参阅 .NET MAUI 中的重用自定义呈现器 并将 自定义呈现器迁移到 Xamarin.Forms .NET MAUI 处理程序。
效果可以在 .NET MAUI 应用中重复使用。 有关详细信息,请参阅 重复使用效果。
如果需要将特定于平台的服务迁移到 .NET MAUI,请使用 AddTransient(IServiceCollection, Type) 方法将指定类型的瞬时服务添加到指定的 IServiceCollection 中。
然后,应将任何平台代码、资源和配置复制到多项目 .NET MAUI 应用。
命名空间更改
命名空间在从 Xamarin.Forms 转移到 .NET MAUI 时已更改,并且 Xamarin.Essentials 功能现在属于 .NET MAUI。 若要进行命名空间更新,请为以下命名空间执行查找和替换:
.NET MAUI 项目使用隐式 global using
指令。 使用此功能可以删除 using
命名空间的 Xamarin.Essentials
指令,而无需将它们替换为等效的 .NET MAUI 命名空间。
此外,默认 XAML 命名空间已从 .NET MAUI 中的 http://xamarin.com/schemas/2014/forms
变更为 Xamarin.Forms。 因此,应将所有出现的地方 xmlns="http://xamarin.com/schemas/2014/forms"
替换为 xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
。
注释
您可以使用 Xamarin.Forms
快速更新您的 Microsoft.Maui
命名空间到 ,前提是已安装 升级助手。
API 变动
一些 API 在从 Xamarin.Forms 迁移到 .NET MAUI 的过程中发生了更改。 这是多种原因,包括删除由成为 .NET MAUI 一部分而 Xamarin.Essentials 引起的重复功能,并确保 API 遵循 .NET 命名准则。 以下部分将讨论这些更改。
颜色变化
在Xamarin.Forms中,Xamarin.Forms.Color
结构允许使用Color值构造double
对象,并提供命名颜色,例如Xamarin.Forms.Color.AliceBlue
。 在 .NET MAUI 中,此功能已分为 Microsoft.Maui.Graphics.Color 类和 Microsoft.Maui.Graphics.Colors 类。
在Microsoft.Maui.Graphics.Color命名空间中的Microsoft.Maui.Graphics类允许您使用Color值、float
值和byte
值来构造int
对象。 该 Microsoft.Maui.Graphics.Colors 类也位于命名空间中 Microsoft.Maui.Graphics ,主要提供相同的命名颜色。 例如,使用 Colors.AliceBlue 来指定 AliceBlue
颜色。
下表显示了结构与Xamarin.Forms.Color
类之间的 Microsoft.Maui.Graphics.Color API 更改:
Xamarin.Forms 应用程序接口 | .NET MAUI API | 注释 |
---|---|---|
Xamarin.Forms.Color.R |
Microsoft.Maui.Graphics.Color.Red | |
Xamarin.Forms.Color.G |
Microsoft.Maui.Graphics.Color.Green | |
Xamarin.Forms.Color.B |
Microsoft.Maui.Graphics.Color.Blue | |
Xamarin.Forms.Color.A |
Microsoft.Maui.Graphics.Color.Alpha | |
Xamarin.Forms.Color.Hue |
Microsoft.Maui.Graphics.Color.GetHue | Xamarin.Forms 属性在 .NET MAUI 中被替换为方法。 |
Xamarin.Forms.Color.Saturation |
Microsoft.Maui.Graphics.Color.GetSaturation | Xamarin.Forms 属性在 .NET MAUI 中被替换为方法。 |
Xamarin.Forms.Color.Luminosity |
Microsoft.Maui.Graphics.Color.GetLuminosity | Xamarin.Forms 属性在 .NET MAUI 中被替换为方法。 |
Xamarin.Forms.Color.Default |
无 .NET MAUI 等效项。 相反, Microsoft.Maui.Graphics.Color 对象默认为 null . |
|
Xamarin.Forms.Color.Accent |
无 .NET MAUI 等效项。 | |
Xamarin.Forms.Color.FromHex |
Microsoft.Maui.Graphics.Color.FromArgb | Microsoft.Maui.Graphics.Color.FromHex 已过时,将在将来的版本中删除。 |
此外,Microsoft.Maui.Graphics.Color 中的所有数值不是float
,而是double
,如Xamarin.Forms.Color
中所用。
注释
与 Xamarin.Forms 不同,Microsoft.Maui.Graphics.Color 无法隐式转换为 System.Drawing.Color。
布局更改
下表列出了在从 Xamarin.Forms 转移到 .NET MAUI 时已删除的布局 API:
Xamarin.Forms API | .NET MAUI API | 注释 |
---|---|---|
Xamarin.Forms.AbsoluteLayout.IAbsoluteList<T>.Add |
Add 接受三个参数的重载在 .NET MAUI 中不存在。 |
|
Xamarin.Forms.Grid.IGridList<T>.AddHorizontal |
无 .NET MAUI 等效项。 | |
Xamarin.Forms.Grid.IGridList<T>.AddVertical |
无 .NET MAUI 等效项。 | |
Xamarin.Forms.RelativeLayout |
Microsoft.Maui.Controls.Compatibility.RelativeLayout | 在 .NET MAUI 中,RelativeLayout 仅作为用于从 Xamarin.Forms 迁移用户的兼容性控件存在。 请改为使用 Grid ,或添加 xmlns 兼容性命名空间。 |
此外,可以通过将子级添加到布局的 Xamarin.Forms 集合中来将子级添加到代码中的 Children
布局。
Grid grid = new Grid();
grid.Children.Add(new Label { Text = "Hello world" });
在 .NET MAUI 中,集合Children供 .NET MAUI 内部使用,不应直接修改。 代码中应直接将子元素添加到布局中。
Grid grid = new Grid();
grid.Add(new Label { Text = "Hello world" });
重要
任何 Add
布局扩展方法(例如 GridExtensions.Add)都是在布局上调用的,而不是在布局的 Children 集合上调用。
在运行升级后的 .NET MAUI 应用时,你可能会注意到布局行为不同。 有关详细信息,请参阅布局行为更改。Xamarin.Forms
自定义布局更改
创建自定义布局 Xamarin.Forms 的过程包括创建一个继承自 Layout<View>
的类,同时重写 VisualElement.OnMeasure
和 Layout.LayoutChildren
方法。 有关详细信息,请参阅Xamarin.Forms中的自定义布局。
在 .NET MAUI 中,布局类派生自抽象 Layout 类。 此类将跨平台的布局和测量任务委托给布局管理类。 每个布局管理器类实现 ILayoutManager 接口,该接口规定必须提供 Measure 和 ArrangeChildren 的实现:
- 实现 Measure 调用 IView.Measure 布局中的每个视图,并返回给定约束的布局的总大小。
- ArrangeChildren 的实现确定每个视图应放置在布局边界内的位置,并根据每个视图的相应边界调用 Arrange。 返回值是布局的实际大小。
有关详细信息,请参阅 自定义布局。
设备更改
Xamarin.Forms 具有一个 Xamarin.Forms.Device
类,可帮助你与运行应用的设备和平台进行交互。 .NET MAUI Microsoft.Maui.Controls.Device中的等效类已弃用,其功能被多个类型替换。
下表显示了 Xamarin.Forms.Device
类中的功能所对应的 .NET MAUI 替换项:
地图更改
在 Xamarin.Forms 命名空间中,控件 Map
和关联的类型。 在 .NET MAUI 中,此功能已移至 Microsoft.Maui.Controls.Maps 和 Microsoft.Maui.Maps 命名空间。 某些属性已重命名,某些类型已替换为等效类型。Xamarin.Essentials
下表显示了命名空间中 Xamarin.Forms.Maps
功能的 .NET MAUI 替换项:
Xamarin.Forms API(应用程序接口) | .NET MAUI API | 注释 |
---|---|---|
Xamarin.Forms.Maps.Map.HasScrollEnabled |
Microsoft.Maui.Controls.Maps.Map.IsScrollEnabled | |
Xamarin.Forms.Maps.Map.HasZoomEnabled |
Microsoft.Maui.Controls.Maps.Map.IsZoomEnabled | |
Xamarin.Forms.Maps.Map.TrafficEnabled |
Microsoft.Maui.Controls.Maps.Map.IsTrafficEnabled | |
Xamarin.Forms.Maps.Map.MoveToLastRegionOnLayoutChange |
无 .NET MAUI 等效项。 | |
Xamarin.Forms.Maps.Pin.Id |
Microsoft.Maui.Controls.Maps.Pin.MarkerId | |
Xamarin.Forms.Maps.Pin.Position |
Microsoft.Maui.Controls.Maps.Pin.Location | |
Xamarin.Forms.Maps.MapClickedEventArgs.Position |
Microsoft.Maui.Controls.Maps.MapClickedEventArgs.Location | |
Xamarin.Forms.Maps.Position |
Microsoft.Maui.Devices.Sensors.Location | 类型 Xamarin.Forms.Maps.Position 的成员已更改为 Microsoft.Maui.Devices.Sensors.Location 类型。 |
Xamarin.Forms.Maps.Geocoder |
Microsoft.Maui.Devices.Sensors.Geocoding | 类型 Xamarin.Forms.Maps.Geocoder 的成员已更改为 Microsoft.Maui.Devices.Sensors.Geocoding 类型。 |
.NET MAUI 有两 Map
种类型 - Microsoft.Maui.Controls.Maps.Map 和 Microsoft.Maui.ApplicationModel.Map。
Microsoft.Maui.ApplicationModel命名空间是 .NET MAUI 的一项指令,因此在代码中使用global using
控件时,您必须完全限定Microsoft.Maui.Controls.Maps.Map的使用方式或使用Map
。
在 XAML 中, xmlns
应为 Map 控件添加命名空间定义。 虽然这不是必需的,但它可以防止Polygon
类型和Polyline
类型在Microsoft.Maui.Controls.Maps和Microsoft.Maui.Controls.Shapes命名空间中发生冲突。 有关详细信息,请参阅 “显示地图”。
其他更改
在从 Xamarin.Forms 迁移到 .NET MAUI 的过程中,少量其他 API 已被合并。 下表显示了这些更改:
Xamarin.Forms 应用程序接口 | .NET MAUI API | 注释 |
---|---|---|
Xamarin.Forms.Application.Properties |
Microsoft.Maui.Storage.Preferences | |
Xamarin.Forms.Button.Image |
Microsoft.Maui.Controls.Button.ImageSource | |
Xamarin.Forms.Frame.OutlineColor |
Microsoft.Maui.Controls.Frame.BorderColor | |
Xamarin.Forms.IQueryAttributable.ApplyQueryAttributes |
Microsoft.Maui.Controls.IQueryAttributable.ApplyQueryAttributes | 在中 Xamarin.Forms,该方法 ApplyQueryAttributes 接受参数 IDictionary<string, string> 。 在 .NET MAUI 中,该方法 ApplyQueryAttributes 接受参数 IDictionary<string, object> 。 |
Xamarin.Forms.MenuItem.Icon |
Microsoft.Maui.Controls.MenuItem.IconImageSource |
Xamarin.Forms.MenuItem.Icon 是 Xamarin.Forms.ToolbarItem 的基类,因此 ToolbarItem.Icon 成为 ToolbarItem.IconImageSource 。 |
Xamarin.Forms.OrientationStateTrigger.Orientation |
Microsoft.Maui.Controls.OrientationStateTrigger.Orientation | 在Xamarin.Forms中,OrientationStateTrigger.Orientation 属性的类型为Xamarin.Forms.Internals.DeviceOrientation 。 在 .NET MAUI 中,OrientationStateTrigger.Orientation 属性的类型是 DisplayOrientation。 |
Xamarin.Forms.OSAppTheme |
Microsoft.Maui.ApplicationModel.AppTheme | |
Xamarin.Forms.Span.ForegroundColor |
Microsoft.Maui.Controls.Span.TextColor | |
Xamarin.Forms.ToolbarItem.Name |
Microsoft.Maui.Controls.MenuItem.Text |
Microsoft.Maui.Controls.MenuItem.Text 是 Microsoft.Maui.Controls.ToolbarItem 的基类,因此 ToolbarItem.Name 成为 ToolbarItem.Text 。 |
此外,在应用进入后台后再回到前台时,会在 Android 上调用Xamarin.Forms中的Page.OnAppearing
重写方法。 但是,在同一场景中,iOS 和 Windows 上不会调用此替代方案。 在 .NET MAUI 中,当应用程序在后台运行,然后恢复到前台时,OnAppearing()重写不会在任何平台上被调用。 相反,应该侦听生命周期事件 Window ,以便在应用返回到前台时收到通知。 有关详细信息,请参阅 .NET MAUI 窗口。
原生格式更改
本机表单Xamarin.Forms已成为 .NET MAUI 中的本机嵌入,并使用不同的初始化方法和不同的扩展方法将跨平台控件转换为其本机类型。 有关详细信息,请参阅本机嵌入。
AssemblyInfo 修改
通常在 AssemblyInfo.cs 文件中设置的属性现在可在 SDK 样式项目中使用。 建议将它们从 AssemblyInfo.cs 迁移到每个项目中的项目文件,并删除 AssemblyInfo.cs 文件。
(可选)可以保留AssemblyInfo.cs文件并将项目文件中的属性设置为GenerateAssemblyInfo
false
:
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
有关属性 GenerateAssemblyInfo
的详细信息,请参阅 GenerateAssemblyInfo。
更新应用依赖项
通常,Xamarin.Forms NuGet 包与 .NET 8 不兼容,除非它们是使用 .NET 目标框架标识符(TFM)重新编译的。 但是,Android 应用可以使用面向monoandroid
和monoandroidXX.X
框架的NuGet包。
可以通过查看 NuGet 上的“框架”选项卡来确认包是否与 .NET 8 兼容,并检查它是否列出了下表中显示的兼容框架之一:
兼容的框架 | 不兼容的框架 |
---|---|
net8.0-android、monoandroid、monoandroidXX.X | |
net8.0-ios | monotouch、xamarinios、xamarinios10 |
net8.0-macos | monomac、xamarinmac、xamarinmac20 |
net8.0-tvos | xamarintvos |
xamarinwatchos |
注释
不依赖于上面列出的不兼容框架的 .NET Standard 库仍与 .NET 8 兼容。
如果 NuGet 上的包表示与上述任何兼容框架的兼容性,而不考虑还包括不兼容的框架,则包是兼容的。 可以使用 Visual Studio 中的 NuGet 包管理器将兼容的 NuGet 包添加到 .NET MAUI 库项目。
如果找不到与 .NET 8 兼容的 NuGet 包版本,则应:
- 如果拥有代码,请使用 .NETTFM 重新编译包。
- 请查找 .NET 8 包的预览版。
- 将依赖项替换为 .NET 8 兼容的替代项。
编译和故障排除
解决依赖项后,您应构建您的项目。 任何错误都会引导你完成后续步骤。
小窍门
- 在 Visual Studio 中打开和生成项目之前,请从所有项目中删除所有 bin 和 obj 文件夹,尤其是在更改 .NET 版本时。
- 从 Android 项目中删除 Resource.designer.cs 生成的文件。
下表提供有关克服常见生成或运行时问题的指南:
問题 | 小窍门 |
---|---|
Xamarin.* 命名空间不存在。 |
将命名空间更新为对应的 .NET MAUI 版本。 有关详细信息,请参阅 命名空间更改。 |
API 不存在。 | 将 API 使用情况更新为其 .NET MAUI 等效项。 有关详细信息,请参阅 API 更改。 |
应用程序无法部署。 | 确保所需的平台项目设置为在 Visual Studio 的 Configuration Manager 中部署。 |
应用不会启动。 | 更新每个平台项目的入口点类和应用入口点。 有关详细信息,请参阅 启动已迁移的应用。 |
CollectionView 不滚动。 | 检查容器布局和CollectionView的测量大小。 默认情况下,控件将占用容器允许的尽可能多的空间。 Grid 按自身大小约束子级。 然而,一个 StackLayout 使儿童能够占用超出其界限的空间。 |
弹出窗口在 iOS 设备上显示在页面下方。 | 在 Xamarin.Forms iOS 上,所有弹出窗口都是 UIWindow 实例,而在 .NET MAUI 中,弹出窗口是通过查找当前呈现的 ViewController 然后使用 PresentViewControllerAsync 显示的。 在插件(例如 Mopups)中,为了确保弹出窗口正确显示,您应调用 DisplayAlert(在 .NET 10+ 中为 DisplayAlertAsync)、DisplayActionSheet(在 .NET 10+ 中为 DisplayActionSheetAsync),或从用于 DisplayPromptAsync 弹出窗口的 ContentPage 调用 Mopup 。 |
BoxView 未显示。 | 默认大小的BoxViewXamarin.Forms为 40x40。 .NET MAUI 中的默认大小 BoxView 为0x0。 将 WidthRequest 和 HeightRequest 设置为 40。 |
布局缺少填充、边距或间距。 | 基于 .NET MAUI 样式资源向项目添加默认值。 有关详细信息,请参阅默认值变更详解Xamarin.Forms。 |
自定义布局不起作用。 | 自定义布局代码需要更新才能在 .NET MAUI 中工作。 有关详细信息,请参阅 自定义布局更改。 |
自定义呈现器不起作用。 | 呈现器代码需要更新才能在 .NET MAUI 中工作。 有关详细信息,请参阅 在 .NET MAUI 中使用自定义呈现器。 |
效果无效。 | 效果代码需要更新才能在 .NET MAUI 中工作。 有关详细信息,请参阅 .NET MAUI 中的“使用效果”。 |
SkiaSharp 代码不起作用。 | SkiaSharp 代码需要次要更新才能在 .NET MAUI 中工作。 有关详细信息,请参阅 在 .NET MAUI 中重用代码SkiaSharp。 |
无法访问以前创建的应用属性数据。 | 将应用属性数据迁移到 .NET MAUI 首选项。 有关详细信息,请参阅将数据 从 Xamarin.Forms 应用属性字典迁移到 .NET MAUI 首选项。 |
无法访问以前创建的安全存储数据。 | 将安全存储数据迁移到 .NET MAUI。 有关详细信息,请参阅 从 Xamarin.Essentials 安全存储迁移到 .NET MAUI 安全存储。 |
无法访问以前创建的版本跟踪数据。 | 将版本跟踪数据迁移到 .NET MAUI。 有关详细信息,请参阅 将版本跟踪数据从 Xamarin.Forms 应用迁移到 .NET MAUI 应用。 |