PRISM WPF - 导航每次都会创建新视图

发布于 2024-11-14 18:24:04 字数 655 浏览 0 评论 0原文

我在 WPF 中使用 PRISM 4 导航 API 和 Unity。我有一个树视图,它启动一个 RequestNavigate 并传入所选树节点的 ID (GUID)。

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    ViewNames.SiteView + "?ID=" + site.ID);

在我的模块中,我已经注册了视图/视图模型,如下所示:

_container.RegisterType<SiteDetailsViewModel>();
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView);

当我从树视图中选择不同的节点时,DetailsRegion 按预期显示SiteDetailsView,但是当我喜欢导航回同一节点,创建一个新的视图/视图模型。

我尝试在 IsNavigationTarget(NavigationContext navigationContext) 处中断,但似乎永远不会调用此方法。

我哪里出错了?提前致谢。

I'm using PRISM 4 Navigation API with Unity in WPF. I have a tree-view that initiates a RequestNavigate passing in the selected tree node's ID (GUID).

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    ViewNames.SiteView + "?ID=" + site.ID);

In my module, I have registered the view/view-model like so:

_container.RegisterType<SiteDetailsViewModel>();
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView);

When I select different nodes from the tree view, the DetailsRegion displays the SiteDetailsView as expected, but when I like to navigate back to the same node, a new view/view-model is created.

I tried to break at IsNavigationTarget(NavigationContext navigationContext) but this method appears to never be called.

Where have i gone wrong? Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

变身佩奇 2024-11-21 18:24:04

问题出在我从未预料到的地方...调试导航 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"

一切正常。

结论

ViewModel 的名称必须以该名称开头
与你以前的名字相同
确定您的观点。

我通过将视图更改为:

public class MyView { ... }

并仍然使用相同的视图名称来注册容器和导航来测试这一点:

_container.RegisterType<object, MyView>(ViewNames.SiteView);

...

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    ViewNames.SiteView + "?ID=" + site.ID);

这似乎也有效。因此,视图模型的名称似乎与用于导航到该视图的视图名称有着内在的联系。

注意

仅当您将 IoC 和 Unity 与 PRISM 4 导航 API 结合使用时才会出现这种情况。使用 MEF 时似乎不会发生这种情况。

进一步调查

我还知道一些指南 告诉我们使用typeof(MyView).FullName 在向容器注册视图时...

_container.RegisterType<object, MyView>(typeof(MyView).FullName);

我个人认为这是一个错误。通过使用视图的全名,您可以在视图和任何希望导航到该视图的人之间创建依赖关系...

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    typeof(MyView).FullName + "?ID=" + site.ID);

The problem was in such a place that I never expected... Debugging the Navigation API lead me to the RegionNavigationContentLoader

public object LoadContent(IRegion region, NavigationContext navigationContext)

When i stepped further down the code, I noticed a call to:

protected virtual IEnumerable<object> GetCandidatesFromRegion(
    IRegion region,
    string candidateNavigationContract)

I noticed that the naming here is key to matching the view to the view-model.

In my example, the name for each part was:

public class SiteDetailsViewModel { ... } // ViewModel

public class SiteDetailsView { ... } // View

ViewNames.SiteView = "SiteView" // ViewName constant

When I inadvertently made the following change:

ViewName.SiteView = "SiteDetailsView"

Everthing worked.

Conclusion

The name of the ViewModel must start
with the same name you used to
identify your view.

I tested this out by changing my view to:

public class MyView { ... }

and still using the same view name to register with the container and navigation:

_container.RegisterType<object, MyView>(ViewNames.SiteView);

...

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    ViewNames.SiteView + "?ID=" + site.ID);

This seems to work also. So it seems the name of the View-Model is intrinsically linked to the view name used to navigate to that view.

NOTE

This is only when you're using IoC and Unity with the PRISM 4 Navigation API. This doesn't seem to happen when using MEF.

Further Investigation

I am also aware that some guides have told us to use the typeof(MyView).FullName when registering the view with the Container...

_container.RegisterType<object, MyView>(typeof(MyView).FullName);

I personally think this is a mistake. By using the view's full name, you are creating a depending between the view and any one who wishes to navigate to that view...

_regionManager.RequestNavigate(RegionNames.DetailRegion,
    typeof(MyView).FullName + "?ID=" + site.ID);
萌吟 2024-11-21 18:24:04

View 和 ViewModel 的注册是问题所在。如果只有一种视图,您必须使用不同的生命周期管理器。如果不指定生命周期管理器,则使用 TransientLifetimeManager ,它总是在解析时返回一个新实例。如果只有一个实例,您必须使用 ContainerControlledLifetimeManager 或 HierarchicalLifetimeManager:

_container.RegisterType<SiteDetailsViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView, new ContainerControlledLifetimeManager());

The registration of the View and the ViewModel is the problem. To have only one view you have to use a different lifetime manager. Without specifying a lifetime manager the TransientLifetimeManager is used which always returns a new instance on resolve. To have only one single instance you have to use the ContainerControlledLifetimeManager or the HierarchicalLifetimeManager:

_container.RegisterType<SiteDetailsViewModel>(new ContainerControlledLifetimeManager());
_container.RegisterType<object, SiteDetailsView>(ViewNames.SiteView, new ContainerControlledLifetimeManager());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文