MAUI中Shell.Current.GoToAsync导航耗时过长问题求助
MAUI Shell导航性能异常排查求助
我在MAUI项目开发中遇到Shell导航性能问题,await Shell.Current.GoToAsync(nameof(DetailMenuPage));这条语句执行耗时高达4692ms,但导航前后的业务代码(包括页面Appearing触发的Load命令)总耗时仅168ms左右。
导航触发代码
public async Task SelectItem(object selectedCategorie) { if (selectedCategorie is CategorieMenu) { var cSelectedCategorie = selectedCategorie as CategorieMenu; var sousCategorie = await _serviceToSousCategorieMenu.GetByCategorieMenuId(new List<int> { cSelectedCategorie.CategorieMenuId }); StaticContext.CategorieMenuName = cSelectedCategorie.Name; StaticContext.SousCategorieMenu = sousCategorie; var watch = new System.Diagnostics.Stopwatch(); watch.Start(); await Shell.Current.GoToAsync(nameof(DetailMenuPage)); watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); } }
此处
watch.ElapsedMilliseconds输出为4692ms。
页面加载业务代码
[RelayCommand] public async Task Load() { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var allItem = await _serviceMenuItem.GetBySousCategorieMenuId(StaticContext.SousCategorieMenu.Select(sc => sc.SousCategorieMenuId).ToList()); if (allItem != null && allItem.Count > 0) { var groupedItem = allItem.GroupBy(u => u.SousCategorieMenuId).Select(grp => grp.ToList()).ToList(); Title = StaticContext.CategorieMenuName; groupedItem.ForEach(c => { Items.Add(new CategorieGroup ( StaticContext.SousCategorieMenu.FirstOrDefault(sc => sc.SousCategorieMenuId == c.FirstOrDefault().SousCategorieMenuId).Name, c )); }); } watch.Stop(); Console.WriteLine($"Execution Time: {watch.ElapsedMilliseconds} ms"); }
此处
watch.ElapsedMilliseconds输出为168ms。
补充代码细节
DetailMenuPage构造函数
public DetailMenuPage(DetailMenuPageViewModel vm) { InitializeComponent(); BindingContext = vm; }
DetailMenuPage的XAML代码
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Byron.Page.DetailMenuPage" xmlns:ViewModels="clr-namespace:Byron.ViewModel" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" x:DataType="ViewModels:DetailMenuPageViewModel" xmlns:Models ="clr-namespace:Byron.Model.DTO" xmlns:Converter="clr-namespace:Byron.Helper.Converter" xmlns:IHM ="clr-namespace:Byron.Model.IHM" Routing.Route="DetailPage" Title="{Binding Title}"> <ContentPage.Behaviors> <toolkit:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand}" /> </ContentPage.Behaviors> <ContentPage.Resources> <Converter:DoubleToStringConverter x:Key="doubleToStringConverter" /> </ContentPage.Resources> <ScrollView> <StackLayout> <CollectionView ItemsSource="{Binding Items}" IsGrouped="True" > <CollectionView.GroupHeaderTemplate> <DataTemplate x:DataType="IHM:CategorieGroup"> <StackLayout HorizontalOptions="FillAndExpand"> <Label Text="{Binding GroupTitle}" Style="{StaticResource TitleGroupMenu}"/> </StackLayout> </DataTemplate> </CollectionView.GroupHeaderTemplate> <CollectionView.ItemTemplate> <DataTemplate x:DataType="Models:MenuItem"> <Frame CornerRadius="10" Margin="10" BorderColor="{AppThemeBinding Light=Black, Dark=White}" BackgroundColor="Transparent"> <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand"> <StackLayout Orientation="Horizontal"> <Label Text="{Binding Name}" Style="{StaticResource ItemMenu}" /> <Label Text="{Binding Prix, Converter={StaticResource doubleToStringConverter}}" HorizontalOptions="EndAndExpand" Style="{StaticResource ItemMenu}"/> </StackLayout> <Rectangle HeightRequest="1" BackgroundColor="Black" Margin="0,0,100,0" /> <Label Text="{Binding Description}" VerticalOptions="Center" TextColor="{AppThemeBinding Light=Black, Dark=White}" /> </StackLayout> </Frame> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </StackLayout> </ScrollView> </ContentPage>
ViewModel构造函数
public DetailMenuPageViewModel(Services.SQLite.Interfaces.IServiceMenuItem serviceMenuItem) { _serviceMenuItem = serviceMenuItem; }
排查建议与解决方案
1. 检查路由与依赖注入配置
- 确认
DetailMenuPage的Shell路由注册无重复、无冲突,避免路由解析延迟。 - 确保
DetailMenuPage和对应的ViewModel在依赖注入中注册为瞬态(Transient),单例模式可能引发初始化时的资源竞争。
2. 优化XAML加载性能
- 简化布局嵌套:
CollectionView本身支持滚动,可直接移除外层的ScrollView和StackLayout,减少布局计算开销。 - 启用XAML预编译:在项目文件中添加以下配置,提前编译XAML降低运行时加载耗时:
<PropertyGroup> <MauiXamlCompile>True</MauiXamlCompile> <MauiXamlCompilationMode>Compile</MauiXamlCompilationMode> </PropertyGroup> - 替换高开销控件:用
Border替代Frame(Frame渲染成本更高),并用Grid合并StackLayout嵌套,减少UI元素数量。
3. 排查主线程阻塞
- 使用Visual Studio性能分析工具,监控导航过程中主线程的耗时操作,定位是否存在隐藏的同步阻塞代码。
- 重构
StaticContext数据传递逻辑,避免全局静态变量的线程竞争导致延迟。
4. 调整数据传递与导航逻辑
- 改用Shell导航参数传递数据,替代
StaticContext,将数据加载与导航解耦:
在ViewModel中通过// 导航时传递参数 await Shell.Current.GoToAsync($"{nameof(DetailMenuPage)}?CategorieId={cSelectedCategorie.CategorieMenuId}");QueryProperty接收参数并加载数据,避免导航等待数据准备完成。
5. 预加载页面优化首次导航
- 如果仅首次导航耗时过长,可在App启动时预加载页面,提前完成JIT编译:
// 在App构造函数或启动逻辑中添加 _ = ServiceProvider.GetRequiredService<DetailMenuPage>();
内容的提问来源于stack exchange,提问作者Alexandre S.
相关产品推荐
相关产品推荐

