Xamarin.Forms FreshMVVM 如何在App.xaml.cs校验页面未打开再打开
FreshMVVM 重复推送同页面的校验实现
不需要自己额外维护一份页面打开状态的集合,直接依托FreshMVVM本身托管的导航栈做判断就行,能完全避免自定义状态和实际导航状态不同步的问题,具体实现逻辑如下:
- 核心判断依据:所有通过
FreshPageModelResolver.ResolvePageModel<T>()生成的页面,都会自动把对应的PageModel实例设置为页面的BindingContext,我们只需要遍历当前导航栈里的所有页面,检查是否存在类型匹配的BindingContext,就能判断目标页面是否已经打开。 - 改造后的代码完全兼容你现有的导航调用逻辑:
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () => { var navService = FreshIOC.Container.Resolve<IFreshNavigationService>(FreshMvvm.Constants.DefaultNavigationServiceName); // 获取当前导航栈托管的根NavigationPage,为空说明还没完成导航初始化,直接返回即可 var rootNavPage = navService.CurrentNavigation; if (rootNavPage == null) return; // 收集栈内的普通导航页面 var normalStackPages = rootNavPage.Navigation.NavigationStack; // 如果应用用到了模态弹窗导航,还要把模态栈的页面也纳入判断范围 var modalStackPages = rootNavPage.Navigation.ModalStack; // 判断是否已经打开过目标SomePageModel对应的页面 bool isTargetPageOpened = normalStackPages .Concat(modalStackPages) .Any(page => page.BindingContext is SomePageModel); if (isTargetPageOpened) { // 页面已经打开,直接终止后续推送逻辑,也可以在这里补充逻辑把已有页面切到最顶层 return; } // 执行原有页面推送逻辑 Page page = FreshPageModelResolver.ResolvePageModel<SomePageModel>(); await navService.PushPage(page, null); });
额外注意事项
- 上述逻辑同时覆盖了普通导航和模态导航两种栈的判断,完全和框架本身的导航状态同步,不会出现自定义记录的打开状态和实际栈内容不一致的问题。
- 如果检测到页面已经打开时,你不想直接跳过,而是希望把已经打开的实例直接激活到最前端,不需要重新新建页面,可以在检测到匹配页面后,计算当前栈顶到目标页面的层级差,逐次Pop回退到对应位置即可,不需要走新建页面+Push的流程。
- 针对Android平台内存不足回收页面的场景,因为被回收的页面本身就会从导航栈移除,判断逻辑自然会识别到页面不存在,不会出现误判。
内容的提问来源于stack exchange,提问作者David Shochet
相关产品推荐
相关产品推荐

