MAUI: await Shell.Current.GoToAsync花费了太多时间

huangapple go评论77阅读模式
英文:

MAUI : await Shell.Current.GoToAsync take too much time

问题

I am developing a project using MAUI and I have some issues with the shell navigation.
There is the line in my code:

await Shell.Current.GoToAsync(nameof(DetailMenuPage));

This execution time code is very long. I have some business code before it takes no time compared to the navigation. Also, I have other business which is executed during the navigation (in a command for the Appearing event) and takes no time too.
There is the full code before and during the navigation:

public async Task SelectItem(object selectedCategorie)
{
if (selectedCategorie is CategorieMenu)
{
var cSelectedCategorie = selectedCategorie as CategorieMenu;
var sousCategorie = await _serviceToSousCategorieMenu.GetByCategorieMenuId(new List { 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");
}
}

Here the watch.ElapsedMilliseconds takes 4692 ms.

[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");
}

Here the watch.ElapsedMilliseconds takes 168 ms.

Did I miss something or did you have any tips?

EDIT:

There the constructor of DetailMenuPage:

public DetailMenuPage(DetailMenuPageViewModel vm)
{
InitializeComponent();
BindingContext = vm;
}

The content of DetailMenuPage:


<ContentPage.Behaviors>
<toolkit:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadCommand}" />
</ContentPage.Behaviors>
<ContentPage.Resources>
<Converter:DoubleToStringConverter x:Key="doubleToStringConverter" />
</ContentPage.Resources>



<CollectionView.GroupHeaderTemplate>




</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>









</CollectionView.ItemTemplate>



And the constructor of the view model:

public DetailMenuPageViewModel(Services.SQLite.Interfaces.IServiceMenuItem serviceMenuItem)
{
_serviceMenuItem = serviceMenuItem;
}

英文:

I am developing a project using MAUI and I have some issues with the shell navigation.
There is the line in my code :

await Shell.Current.GoToAsync(nameof(DetailMenuPage));

This execution time code is very long . I have some business code before it takes no time compared to the navigation. Also, I have other business which is executed during the navigation (in a command for the Appearing event) and takes no time too.
There is the full code before and during the navigation :

public async Task SelectItem(object selectedCategorie)
{
   if (selectedCategorie is CategorieMenu)
   {
      var cSelectedCategorie = selectedCategorie as CategorieMenu;
      var sousCategorie = await _serviceToSousCategorieMenu.GetByCategorieMenuId(new List&lt;int&gt; { 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($&quot;Execution Time: {watch.ElapsedMilliseconds} ms&quot;);
   }
}

Here the watch.ElapsedMilliseconds takes 4692 ms.

[RelayCommand]
public async Task Load()
{
   var watch = new System.Diagnostics.Stopwatch();
   watch.Start();
   var allItem = await _serviceMenuItem.GetBySousCategorieMenuId(StaticContext.SousCategorieMenu.Select(sc =&gt; sc.SousCategorieMenuId).ToList());
   if (allItem != null &amp;&amp; allItem.Count &gt; 0)
   {
      var groupedItem = allItem.GroupBy(u =&gt; u.SousCategorieMenuId).Select(grp =&gt; grp.ToList()).ToList();
      Title = StaticContext.CategorieMenuName;
      groupedItem.ForEach(c =&gt;
      {
          Items.Add(new CategorieGroup
          (
             StaticContext.SousCategorieMenu.FirstOrDefault(sc =&gt; sc.SousCategorieMenuId == c.FirstOrDefault().SousCategorieMenuId).Name,
                    c
          ));
      });
   }
   watch.Stop();
   Console.WriteLine($&quot;Execution Time: {watch.ElapsedMilliseconds} ms&quot;);
}

Here the watch.ElapsedMilliseconds takes 168 ms.

Did I miss something or did you have any tips ?

EDIT :

There the constructor of DetailMenuPage :

public DetailMenuPage(DetailMenuPageViewModel vm)
{
	InitializeComponent();
	BindingContext = vm;
}

The content of DetailMenuPage :

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
             x:Class=&quot;Byron.Page.DetailMenuPage&quot;
             xmlns:ViewModels=&quot;clr-namespace:Byron.ViewModel&quot;
             xmlns:toolkit=&quot;http://schemas.microsoft.com/dotnet/2022/maui/toolkit&quot;
             x:DataType=&quot;ViewModels:DetailMenuPageViewModel&quot;
             xmlns:Models =&quot;clr-namespace:Byron.Model.DTO&quot;
             xmlns:Converter=&quot;clr-namespace:Byron.Helper.Converter&quot;
             xmlns:IHM =&quot;clr-namespace:Byron.Model.IHM&quot;
             Routing.Route=&quot;DetailPage&quot;
             Title=&quot;{Binding Title}&quot;&gt;
    &lt;ContentPage.Behaviors&gt;
        &lt;toolkit:EventToCommandBehavior EventName=&quot;Appearing&quot; Command=&quot;{Binding LoadCommand}&quot; /&gt;
    &lt;/ContentPage.Behaviors&gt;
    &lt;ContentPage.Resources&gt;
        &lt;Converter:DoubleToStringConverter x:Key=&quot;doubleToStringConverter&quot; /&gt;
    &lt;/ContentPage.Resources&gt;
    
    
    &lt;ScrollView&gt;
        &lt;StackLayout&gt;
            &lt;CollectionView ItemsSource=&quot;{Binding Items}&quot; IsGrouped=&quot;True&quot; &gt;
                &lt;CollectionView.GroupHeaderTemplate&gt;
                    &lt;DataTemplate x:DataType=&quot;IHM:CategorieGroup&quot;&gt;
                        &lt;StackLayout HorizontalOptions=&quot;FillAndExpand&quot;&gt;
                            &lt;Label Text=&quot;{Binding GroupTitle}&quot; Style=&quot;{StaticResource TitleGroupMenu}&quot;/&gt;
                        &lt;/StackLayout&gt;
                    &lt;/DataTemplate&gt;
                &lt;/CollectionView.GroupHeaderTemplate&gt;
                &lt;CollectionView.ItemTemplate&gt;
                    &lt;DataTemplate x:DataType=&quot;Models:MenuItem&quot;&gt;
                        &lt;Frame CornerRadius=&quot;10&quot; Margin=&quot;10&quot; BorderColor=&quot;{AppThemeBinding Light=Black, Dark=White}&quot; BackgroundColor=&quot;Transparent&quot;&gt;
                            &lt;StackLayout Orientation=&quot;Vertical&quot; HorizontalOptions=&quot;FillAndExpand&quot; VerticalOptions=&quot;CenterAndExpand&quot;&gt;
                                &lt;StackLayout Orientation=&quot;Horizontal&quot;&gt;
                                    &lt;Label Text=&quot;{Binding Name}&quot; Style=&quot;{StaticResource ItemMenu}&quot; /&gt;
                                    &lt;Label Text=&quot;{Binding Prix, Converter={StaticResource doubleToStringConverter}}&quot; HorizontalOptions=&quot;EndAndExpand&quot; Style=&quot;{StaticResource ItemMenu}&quot;/&gt;
                                &lt;/StackLayout&gt;
                                &lt;Rectangle HeightRequest=&quot;1&quot; BackgroundColor=&quot;Black&quot; Margin=&quot;0,0,100,0&quot; /&gt;
                                &lt;Label Text=&quot;{Binding Description}&quot; VerticalOptions=&quot;Center&quot; TextColor=&quot;{AppThemeBinding Light=Black, Dark=White}&quot; /&gt;
                            &lt;/StackLayout&gt;
                        &lt;/Frame&gt;
                    &lt;/DataTemplate&gt;
                &lt;/CollectionView.ItemTemplate&gt;
            &lt;/CollectionView&gt;
        &lt;/StackLayout&gt;
    &lt;/ScrollView&gt;
&lt;/ContentPage&gt;

And the constructor of the view model :

 public DetailMenuPageViewModel(Services.SQLite.Interfaces.IServiceMenuItem serviceMenuItem)
 {
     _serviceMenuItem = serviceMenuItem;
 }

答案1

得分: 3

<ScrollView>
    <StackLayout>
        <CollectionView ItemsSource="{Binding Items}" IsGrouped="True">
非垂直受限制的视觉元素不应该放在其他非垂直受限制的容器内。

有趣的是,当人们抱怨性能时,我通常看到上述两者的组合。您的代码远远超出了这个范围。

限制您的VisualElements。无论是通过请求高度还是其他方式。

我认为我可以安全地推荐编辑:

    <Grid>
         <CollectionView...
(完全不知道您试图做什么)
英文:
 &lt;ScrollView&gt;
        &lt;StackLayout&gt;
            &lt;CollectionView ItemsSource=&quot;{Binding Items}&quot; IsGrouped=&quot;True&quot; &gt;

Non-vertically restricted visual elements should not be inside other non-vertically restricted containers.

The interesting part is that I usually see combination of two of those above, when people complain about performance. Your code goes way beyond that.

Limit your VisualElements. Be it with requesting height or otherwise.

I think I can safely recommend the edit:

&lt;Grid&gt;
     &lt;CollectionView...

(without having any idea what you are trying to do)

答案2

得分: 0

  1. 除了 H.A.H 的回答之外,请考虑以下更改:

    1.1 你需要使用 ScrollView 吗?CollectionView 已经知道如何滚动。如果你移除 ScrollView,那么也应该移除 H.A.H 的回答中的 StackLayout(或者 Grid):

    <CollectionView
    
  2. 无论何时使用 StackLayout,都要更改为 VerticalStackLayoutHorizontalStackLayout,取决于方向。

  3. 使用 Border 代替 FrameFrame 保留了与 Xamarin 的向后兼容性,但使用了旧的渲染方法。Frame 的文档建议使用 Border

  4. 你的 Load 方法在 Appearing 事件期间运行。在填充集合时,不要在那个时候使用 Items.Add(我认为),因为每次添加都会触发布局逻辑。相反,建立一个本地变量的集合,然后将其分配给 Items

var items = new ... Items 相同的类型...();
...
items.Add(...);   // 添加到本地的 `items` 而不是 `Items`。
...
// 当所有项目都添加完毕时。
Items = items;
  1. 考虑在 &lt;CollectionView.ItemTemplate&gt; 内设置 HeightRequest。这适用于外部布局。除非你有 FrameBorder,否则将其放在框架/边框的内容上:&lt;VerticalStackLayout HeightRequest=&quot;99&quot; ...&gt;。用适当的高度替换 "99"。固定高度的项目布局要快得多。
英文:

In addition to H.A.H's answer, consider these changes:

  1. Do you need ScrollView? CollectionView knows how to scroll. If you eliminate ScrollView, then also remove the StackLayout (or Grid from H.A.H.'s answer).:
&lt;ScrollView&gt;
    &lt;StackLayout&gt;
        &lt;CollectionView

becomes:

&lt;CollectionView
  1. Whereever you use StackLayout, change to VerticalStackLayout or HorizontalStackLayout, depending on direction.

  2. Use Border instead of Frame. Frame was kept for backwards compatibility with Xamarin, but uses an old rendering approach. The Frame doc recommends using Border instead.

  3. Your Load method runs during Appearing event. Don't use Items.Add at that time, when filling the collection. (I think) this triggers layout logic on each Add. Instead, build the collection in a local variable, then assign it to Items:

var items = new ...same-type-as-Items...();
...
items.Add(...);   // Add to local `items` instead of `Items`.
...
// When all items have been added.
Items = items;
  1. Consider setting HeightRequest inside &lt;CollectionView.ItemTemplate&gt;. This goes on the outer layout. Except when you have Frame or Border put it on the content of the frame/border: &lt;VerticalStackLayout HeightRequest=&quot;99&quot; ...&gt;. Replace "99" with whatever height looks good. Fixed-height items are MUCH faster to lay out.

huangapple
  • 本文由 发表于 2023年5月15日 03:36:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249355.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定