You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MAUI Shell中模拟Prism的OnNavigated导航方法?

在MAUI Shell中模拟Prism的INavigationAware导航生命周期方法

方法1:封装页面基类消除重复代码

创建通用的ContentPage基类,在基类中统一处理导航生命周期事件,再定义ViewModel接口规范导航方法,避免每个页面重复编写相同逻辑。

实现步骤:

  1. 定义ViewModel导航接口
public interface IPageNavigationAware
{
    Task OnNavigatedToAsync(NavigatedToEventArgs args);
    Task OnNavigatedFromAsync(NavigatedFromEventArgs args);
}
  1. 构建页面基类
public class BaseNavigationPage : ContentPage
{
    protected override async void OnNavigatedTo(NavigatedToEventArgs args)
    {
        base.OnNavigatedTo(args);
        if (BindingContext is IPageNavigationAware viewModel)
        {
            await viewModel.OnNavigatedToAsync(args);
        }
    }

    protected override async void OnNavigatedFrom(NavigatedFromEventArgs args)
    {
        base.OnNavigatedFrom(args);
        if (BindingContext is IPageNavigationAware viewModel)
        {
            await viewModel.OnNavigatedFromAsync(args);
        }
    }
}
  1. 页面与ViewModel对接
// 页面代码,继承基类
public partial class DetailPage : BaseNavigationPage
{
    public DetailPage(DetailViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

// ViewModel代码,实现导航接口
public class DetailViewModel : ObservableObject, IPageNavigationAware
{
    [QueryProperty(nameof(ItemId), "itemId")]
    public string ItemId { get; set; }

    public async Task OnNavigatedToAsync(NavigatedToEventArgs args)
    {
        // 复用原OnNavigatedTo中的异步逻辑,比如加载后端数据
        await LoadTargetData(ItemId);
    }

    public async Task OnNavigatedFromAsync(NavigatedFromEventArgs args)
    {
        // 处理页面离开时的逻辑,比如保存临时状态
        await SavePageState();
    }

    private async Task LoadTargetData(string itemId)
    {
        // 后端数据获取实现
    }

    private async Task SavePageState()
    {
        // 状态保存实现
    }
}

方法2:通过Shell全局导航事件绑定ViewModel逻辑

订阅Shell的导航事件,在全局层面触发ViewModel的导航方法,无需修改页面基类。

实现步骤:

  1. 复用方法1中的IPageNavigationAware接口
  2. 在AppShell中注册导航事件
public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
        Navigated += OnShellNavigated;
        Navigating += OnShellNavigating;
    }

    private async void OnShellNavigated(object sender, ShellNavigatedEventArgs e)
    {
        if (CurrentPage?.BindingContext is IPageNavigationAware viewModel)
        {
            var args = new NavigatedToEventArgs(e.Current.Location, e.Source);
            await viewModel.OnNavigatedToAsync(args);
        }
    }

    private async void OnShellNavigating(object sender, ShellNavigatingEventArgs e)
    {
        if (CurrentPage?.BindingContext is IPageNavigationAware viewModel)
        {
            var args = new NavigatedFromEventArgs(e.Target.Location, e.Source);
            await viewModel.OnNavigatedFromAsync(args);
        }
    }
}

解决NavigatedFromEventArgs缺失来源参数问题

如果需要获取来源页面的解析参数,可通过两种方式处理:

  • 导航时额外传递来源标识参数:
await Shell.Current.GoToAsync($"//DetailPage?itemId={id}&sourcePage=ListPage");

之后在ViewModel的OnNavigatedToAsync中解析sourcePage参数即可。

  • 从导航栈中提取上一页信息:
private async void OnShellNavigated(object sender, ShellNavigatedEventArgs e)
{
    var navigationStack = Shell.Current.Navigation.NavigationStack;
    if (navigationStack.Count >= 2)
    {
        var previousPage = navigationStack[navigationStack.Count - 2];
        if (previousPage.BindingContext is ListPageViewModel listVm)
        {
            var sourceParam = listVm.SelectedItemId;
            if (CurrentPage.BindingContext is DetailViewModel detailVm)
            {
                detailVm.SourceItemId = sourceParam;
            }
        }
    }

    if (CurrentPage?.BindingContext is IPageNavigationAware viewModel)
    {
        await viewModel.OnNavigatedToAsync(new NavigatedToEventArgs(e.Current.Location, e.Source));
    }
}

异步操作适配

上述两种方法均采用异步ViewModel方法,完全兼容原Prism中OnNavigatedTo的异步数据加载逻辑,无需重构现有业务代码。


内容的提问来源于stack exchange,提问作者Vering

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:40:24