我在WPF中使用带有Unity的PRISM 4 Navigation API。我有一个树视图,它启动 RequestNavigate 传递所选树节点的ID( GUID )。
_regionManager.RequestNavigate(RegionNames.DetailRegion,
ViewNames.SiteView + "?ID=" + site.ID);
在我的模块中,我已经注册了视图/视图模型:
_container.RegisterType<SiteDetailsViewModel>();
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView);
当我从树视图中选择不同的节点时, DetailsRegion 会按预期显示 SiteDetailsView ,但是当我想导航回同一节点时,会出现一个新视图/ view-model已创建。
我试图在IsNavigationTarget(NavigationContext navigationContext)
处休息,但这种方法似乎永远不会被调用。
我哪里出错了?提前谢谢。
答案 0 :(得分:7)
问题出现在我从未想过的地方......调试导航API会引导我进入RegionNavigationContentLoader
public object LoadContent(IRegion region, NavigationContext navigationContext)
当我进一步深入代码时,我注意到了一个电话:
protected virtual IEnumerable<object> GetCandidatesFromRegion(
IRegion region,
string candidateNavigationContract)
我注意到这里的命名是将视图与视图模型匹配的关键。
在我的例子中,每个部分的名称是:
public class SiteDetailsViewModel { ... } // ViewModel
public class SiteDetailsView { ... } // View
ViewNames.SiteView = "SiteView" // ViewName constant
当我无意中做出以下改变时:
ViewName.SiteView = "SiteDetailsView"
Everthing工作。
<强>结论强>
必须启动ViewModel的名称 与你以前的名字相同 确定你的观点。
我通过将观点更改为:
来测试了这一点public class MyView { ... }
仍然使用相同的视图名称注册容器和导航:
_container.RegisterType<object, MyView>(ViewNames.SiteView);
...
_regionManager.RequestNavigate(RegionNames.DetailRegion,
ViewNames.SiteView + "?ID=" + site.ID);
这似乎也有效。因此,View-Model的名称似乎与用于导航到该视图的视图名称本质上相关联。
注意强>
仅当您将IoC和Unity与PRISM 4 Navigation API一起使用时。使用MEF时似乎没有发生这种情况。
进一步调查
我也知道有些guides告诉我们在使用容器注册视图时使用typeof(MyView).FullName
...
_container.RegisterType<object, MyView>(typeof(MyView).FullName);
我个人认为这是一个错误。通过使用视图的全名,您将在视图和任何希望导航到该视图的人之间创建依赖...
_regionManager.RequestNavigate(RegionNames.DetailRegion,
typeof(MyView).FullName + "?ID=" + site.ID);
答案 1 :(得分:0)
注册View和ViewModel是个问题。要只有一个视图,您必须使用不同的生命周期管理器。如果不指定生命周期管理器,则使用TransientLifetimeManager
,它始终在resolve上返回新实例。要只有一个实例,您必须使用ContainerControlledLifetimeManager
或HierarchicalLifetimeManager
:
_container.RegisterType<SiteDetailsViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView, new ContainerControlledLifetimeManager());