在 dotNET MAUI 中使用 Shell 导航,确保页面转换始终具有动画效果并在不同设备上尽可能流畅地执行的最佳(最可靠)方法是什么?
我确实找到了最简单的解决方案,但我想知道是否有更好的方法。我目前的做法似乎不太可靠,尤其是在不同的(较慢和较快)设备上。这真的是最好/最可接受的方式吗?
更新已接受的答案:
接受的答案对我来说产生了巨大的影响!在我的整个应用程序中,许多对象列表都可以加载到 GlobalViewModel 中。我从来不知道我复印了这么多。这加快了我整个申请每一页的速度!
实际问题:
我注意到我的一个页面需要加载的数据稍多一些。虽然在我看来仍然是一个相当可以接受的量,但页面转换不会显示,因为加载数据会导致滞后。
我目前的解决方案:
我正在使用 Shell
await Shell.Current.GoToAsync($"{nameof(PageName)}", true, Params);
导航到一个页面,这是我将拥有的目标页面的一个非常原始/简单的示例:
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"
xmlns:m="clr-namespace:MauiApp1.Models"
xmlns:tk="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:vm="clr-namespace:MauiApp1.ViewModels"
x:DataType="vm:PageNameViewModel">
<ContentPage.Behaviors>
<tk:EventToCommandBehavior Command="{Binding OnAppearingCommand}" EventName="Appearing"/>
</ContentPage.Behaviors>
<StackLayout>
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="m:Item">
<VerticalStackLayout>
<!-- Using item data here -->
</VerticalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
视图模型:
我基本上是先延迟
OnAppearing()
中的所有内容,然后再实际填充页面:
public class PageNameViewModel : BaseViewModel, IQueryAttributable
{
private List<Item> items { get; set; } = new();
public ObservableCollection<Item> Items { get; set; } = new();
public Command OnAppearingCommand { get; private set; }
public PageNameViewModel()
{
OnAppearingCommand = new Command(OnAppearing);
}
public void ApplyQueryAttributes(IDictionary<string, object> Params)
{
items = Params["Items"] as items;
}
private async void OnAppearing()
{
// Delay here to wait for page animation, before populating the page:
await Task.Delay(500);
foreach (var item in items)
{
Items.Add(item);
}
}
}
请注意,在我的例子中,由于
Appearing
接口,我必须在 ViewModel 中的 IQueryAttributable
事件中加载数据。属性是在构造函数之后但在填充视图的出现事件之前通过查询参数设置的。我正在使用 MAUI Community Toolkit 将页面出现事件转换为命令。
我认为这可能不太可靠,因为在较旧且较慢的设备上,延迟时间可能太短。在高端设备上,延迟时间甚至可能变得明显且烦人。
这是可以接受的做法吗?
在您移动到该页面之前,这些项目似乎是已知的。为什么页面需要有项目的副本?相反,让我们参考原始实例。
假设我们有一个
GlobalViewModel
单例,并且在其中放置 ObservableCollection
。目的是让 ObservableCollection
可用于您的整个应用程序。
public GlobalViewModel
{
public ObservableCollection<Item> Items { get; } = new();
}
请注意,对于内联(如上所述)或在构造函数中初始化的集合,您只需要
get;
。
在您的
MauiProgram.cs
中将其注册为单例以进行依赖注入:
builder.Services.AddSingleton<GlobalViewModel>();
builder.Services.AddTransient<PageNameViewModel>();
然后对于您的
PageNameViewModel
,您可以通过构造函数注入参数传入GlobalViewModel
单例:
public PageViewModel
{
public GlobalViewModel Global { get; }
public PageViewModel(GlobalViewModel Global)
{
this.Global = Global;
}
}
前面提到过,由于属性是在构造函数中定义的,所以我们只需要对属性使用
get;
权限即可。
在您的 XAML 中,我们可以通过
Global.Items
访问集合:
<CollectionView ItemsSource="{Binding Global.Items}">