关于 xamarin-forms-migration
面向 Xamarin.Forms 项目的迁移参考,指导开发者将应用迁至 .NET MAUI。内容涵盖迁移步骤、布局陷阱及弃用 API 检查。
主要功能
- 01新建单项目并迁移代码
- 02更新命名空间与 NuGet 依赖
- 03将 Renderer 迁移为 Handler
- 04将 Effect 迁移为 Behavior
- 05排查布局与 API 兼容问题
适用场景
- 01规划 Xamarin.Forms 应用迁移
- 02修复 MAUI 布局异常
- 03替换自定义 Renderer 和 Effect
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill xamarin-forms-migration安装后在 Claude Code 中输入/xamarin-forms-migration确认已加载。
附带文件references/forms-migration-api.md
详细介绍
Xamarin.Forms → .NET MAUI 迁移
项目模板、命名空间表、API 弃用表和参考代码,请参阅 references/forms-migration-api.md。
⚠️ 不要使用 .NET Upgrade Assistant。 直接应用命名空间重命名、项目文件更新和包替换。每批更改后都要构建,并根据编译器错误指导下一轮修复。
迁移工作流
- 创建新的 .NET MAUI 项目(单项目——多项目会导致 AOT/构建错误)
- 将跨平台代码和平台代码复制到
Platforms/<platform>/ - 更新命名空间(XAML + C# + Essentials——参阅
references/forms-migration-api.md) - 修复布局行为变更(见下文)
- 将渲染器迁移到处理程序(不要使用垫片渲染器)
- 将效果迁移到行为
- 移除
Microsoft.Maui.Controls.Compatibility包 - 更新 NuGet 依赖项
- 迁移应用数据存储
- 删除
bin//obj//Resource.designer.cs,然后构建并迭代测试 - 对照 .NET 10 弃用 API 列表进行验证
策略: 创建新项目并将代码复制进去——不要直接修改现有项目文件。
关键布局陷阱
⚠️ 默认间距已变为零
MAUI 会将 Xamarin.Forms 中设为 6 的间距归零。你的布局会在毫无提示的情况下出错:
<Grid>...</Grid>
<StackLayout>...</StackLayout>
<Style TargetType="Grid">
<Setter Property="ColumnSpacing" Value="6"/>
<Setter Property="RowSpacing" Value="6"/>
</Style>
实践建议: 明确指定所有布局值——不要依赖平台默认值。
⚠️ *AndExpand 已过时——不会静默警告
<StackLayout>
<Label Text="Hello world!"/>
<Image VerticalOptions="FillAndExpand" Source="dotnetbot.png"/>
</StackLayout>
<Grid RowDefinitions="Auto, *">
<Label Text="Hello world!"/>
<Image Grid.Row="1" Source="dotnetbot.png"/>
</Grid>
实践建议: 扁平化布局树。将嵌套层级替换为单个 Grid 布局。
StackLayout 中的 ScrollView 不会滚动
放在 StackLayout 中的 ScrollView 会扩展到完整内容高度(无法滚动)。应将 ScrollView 放在具有约束行的 Grid 中。
其他布局陷阱
| 问题 | 修复方法 |
|---|---|
| 未声明 Grid 列/行 → 布局出错 | 始终显式添加 ColumnDefinitions/RowDefinitions |
Frame 的测量方式不同 | 迁移到带有 StrokeShape 的 Border |
BoxView 不可见(MAUI 中默认大小为 0×0) | 设置显式的 WidthRequest/HeightRequest |
RelativeLayout | 替换为 Grid(仅兼容性命名空间中提供) |
渲染器 → 处理程序迁移
⚠️ 将所有渲染器迁移到处理程序。不要使用垫片渲染器——它们会创建父级包装视图,影响性能。
首选:使用映射器方法自定义现有处理程序:
// ✅ Extend existing handler — no new class needed
Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("NoBorder", (handler, view) =>
{
#if ANDROID
handler.PlatformView.Background = null;
#elif IOS || MACCATALYST
handler.PlatformView.BorderStyle = UIKit.UITextBorderStyle.None;
#endif
});
对于全新的原生视图,请创建完整的处理程序(参阅 maui-custom-handlers 技能)。
效果 → 行为
⚠️ 效果现在是行为——这需要重新设计,而不只是重命名。
对于新开发,优先使用行为或处理程序映射器自定义,而不是效果。
⚠️ 不要使用兼容性包
Microsoft.Maui.Controls.Compatibility 会引发一系列兼容性问题。请移除它,并使用原生方式重新构建布局。
已停用的依赖项
- App Center 已停用 → 替换为 Sentry、Azure Monitor 或类似产品
- Visual Studio for Mac 已停用 → 使用 VS Code 或 Rider
Android 特定警告
- Android 迁移比 iOS 难得多——预计会出现更多 UI 错误
- OEM 特定的渲染差异无法在模拟器上复现——请在实体设备上测试
- 阴影渲染会因 OEM/API 级别而异——请在平台特定的处理程序代码中实现
- 处理程序级别的属性变更不会在主题切换时自动更新——请手动处理主题变更
.NET 10 API 时效性警告
迁移是完全跳过弃用 API 的绝佳时机。不要将 Xamarin.Forms 代码迁移到即将弃用的 MAUI API。请参阅 references/forms-migration-api.md 中完整的弃用 API 表,并运行 maui-current-apis 技能。
常见故障排除
| 问题 | 解决方法 |
|---|---|
不存在 Xamarin.* 命名空间 | 更新为对应的 Microsoft.Maui.* 命名空间 |
| CollectionView 无法滚动 | 放入 Grid 中(而非 StackLayout),以限制尺寸 |
| iOS 上弹出窗口显示在页面下方 | 使用 ContentPage 的 DisplayAlert |
| 缺少内边距/外边距/间距 | 添加显式值或隐式样式 |
| 自定义渲染器无法正常工作 | 迁移到处理程序 |
| SkiaSharp 无法正常工作 | 更新为 SkiaSharp.Views.Maui 包 |
| 无法访问 App.Properties 数据 | 迁移到 Preferences |
快速检查清单
- ☐ 创建了新的 .NET MAUI 项目(单项目)
- ☐ 复制了跨平台代码和平台代码
- ☐ 将 XAML 命名空间更新为
http://schemas.microsoft.com/dotnet/2021/maui - ☐ 将
Xamarin.Forms.*命名空间替换为Microsoft.Maui.* - ☐ 将
Xamarin.Essentials替换为拆分后的 MAUI 命名空间 - ☐ 为 Grid 添加了显式的
ColumnDefinitions/RowDefinitions - ☐ 将
*AndExpand替换为 Grid 布局 - ☐ 添加了显式的间距/内边距值(MAUI 默认值为 0)
- ☐ 将渲染器迁移到处理程序(而非通过垫片兼容渲染器)
- ☐ 将效果迁移到行为或 MAUI 效果
- ☐ 移除了
Microsoft.Maui.Controls.Compatibility包 - ☐ 更新了 NuGet 依赖项以兼容 .NET
- ☐ 迁移了 App.Properties、SecureStorage、VersionTracking 数据
- ☐ 删除了
bin/、obj/和Resource.designer.cs - ☐ 在实体 Android 设备上进行了测试
- ☐ 分析了性能
- ☐ 确认没有已弃用的 .NET 10 API(运行 maui-current-apis 技能)