如何在MAUI Shell中模拟Prism的OnNavigated导航方法?
方法1:封装页面基类消除重复代码
创建通用的ContentPage基类,在基类中统一处理导航生命周期事件,再定义ViewModel接口规范导航方法,避免每个页面重复编写相同逻辑。
实现步骤:
- 定义ViewModel导航接口
public interface IPageNavigationAware { Task OnNavigatedToAsync(NavigatedToEventArgs args); Task OnNavigatedFromAsync(NavigatedFromEventArgs args); }
- 构建页面基类
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); } } }
- 页面与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中的
IPageNavigationAware接口 - 在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
相关产品推荐
相关产品推荐

