【发布时间】:2016-09-29 17:55:35
【问题描述】:
我使用 Prism 5.0,但在配置它以重用现有视图时遇到了麻烦。每当调用IRegionManager.RequestNavigate(string regionName, Uri source) 时,它都会创建一个新视图,而不是使用之前创建的视图。奇怪的是,CLRProfiler 还表明 Prism 的区域管理器保留对所有先前创建的视图实例的引用,从而导致内存泄漏。
我的视图模型实现INavigationAware,并在IsNavigationTarget() 中返回true,但该方法从未被调用。我也尝试在视图上实现它,结果相同。
作为测试,我在视图上实现了IActiveAware,这表明当我导航到另一个视图时它被停用(我不确定这是否相关)。
我发现了这个问题:PRISM WPF - Navigation creates new view every time,但我的 V-VM 命名约定与答案匹配(顺便说一下,我使用 AutoFac)。
我只找到了一种解决方法:在视图模型的 INavigationAware.OnNavigatedFrom() 实现中使用 NavigationContext.NavigationService.Region.Remove() 从区域中删除活动视图。当我这样做时,Prism 的区域经理会释放对视图的引用。这可行,但总是在需要时重新创建视图似乎效率低下。
几乎所有关于 SO 的相关问题都询问如何在导航事件上创建新视图,因此我假设默认行为是重用视图。我这里需要指点。
编辑
我们使用 AutoFac 的 AutofacExtensions.RegisterTypeForNavigation<T>(this ContainerBuilder builder, string name = null) 来注册视图。我们确实使用IRegionManager.RequestNavigate() 在视图之间导航。 INavigationAware 在 ViewModel 上实现。然而,虽然INavigationAware.OnNavigatedTo() 和OnNavigatedFrom() 被调用,但IsNavigationTarget() 永远不会被调用(即使视图实现了INavigationAware,后者也不会被调用)。
我可以通过在视图的 ctor 中设置断点来检测是否创建了新视图。 CLRProfiler 堆转储还显示,区域管理器具有与它被导航到的次数一样多的视图实例。 ViewModel 只创建一次,因为它们在 AutoFac 中注册为单实例。
作为临时措施,我们让视图实现了IRegionMemberLifetime,其中KeepAlive 返回false。这不是很有效,因为每次需要时都会重新创建视图,但它会阻止区域管理器保留以前的视图。
【问题讨论】:
-
你需要使用 IRegionMemberLifetime 和 KeepAlive 属性。
-
@AyyappanSubramanian 如果视图实现了 IRegionMemberLifetime,并且 KeepAlive 返回 true,则区域管理器保留对视图的引用,但在导航到时创建一个新的引用(如果视图没有,则必须是默认值'不实施 IRML)。如果 KeepAlive 返回 false,则视图被丢弃,因此需要重新创建。我的问题是如何让 Prism 重用原始视图,所以这不是解决方案。
-
我目前也遇到了同样的问题,虽然不是我所有的观点。似乎是特定页面下方的任何内容都导致了我的问题。