ViewModel的构造函数在导航时再次被调用,因此信使订阅再次被订阅

我正在使用MvvmCross框架构建跨平台的移动应用程序。

由于我想在ViewModels之间共享信息,我使用内置的MvxMessenger在ViewModel的构造函数中注册通知。
让我们假设一条名为ShowAdsMsg的消息,然后ViewModel如下所示:

 public class AdsViewModel : BaseLookersViewModel, IAdsViewModel { private MvxSubscriptionToken _showAdsMsgToken; public AdsViewModel() { _showAdsMsgToken = MvxMessenger.Subscribe(message => onShowAdsNavigation(), MvxReference.Weak); MyMessenger.PublishLastMessage(); } private void onShowAdsNavigation() { //Do Stuff } } 

关于MyMessenger事情:
ViewModel的实际导航是从MainViewModel执行的。
由于在导航本身的那一刻, AdsViewModel还不存在,从MainViewModel发布的消息无法到达它。
所以,我的想法是天真地“记住”消息并在新的ViewModel准备就绪时发布它。
所以现在来自MainViewModel的导航调用看起来像这样:

  private void navigate() { MyMessenger.RememberMessage(new ShowAdsMsg(this)); ShowViewModel( ); } 

我现在能够导航到ViewModel,并且成功捕获了所有通知。

然而…
当我按下设备上的BACK按钮并重新导航到同一个ViewModel时,
正在再次调用构造函数,因此重新发生消息订阅。
因此,当消息到达时, onShowAdsNavigation()处理程序被触发两次!

我找到了这篇类似的post,讨论了如何正确处理ViewModel的问题,
但它不包含我的问题的直接解决方案。

我需要的是一个解决方案。 它可以是以下之一:

  1. 想法如何不订阅ViewModel的ctor上的消息。
  2. 有关如何以及何时正确处置ViewModel的指导。
  3. 解释为什么再次调用构造函数,以及如何避免这种情况。
  4. ViewModel信息消息传递的完全不同方法。

在此先感谢您的帮助!

编辑:我发现这个 SO答案,它基本上回答了上面列表中的第3项。 不过,我想知道我应该采取什么方法来处理信使问题。

另一个编辑:我validation了MvvmCross教程N-05- MultiPage存在相同的行为。 我只是向SecondViewModel添加了一个ctor,在每次BACK + Renavigate之后我在它内部打了一个断点。

解释为什么再次调用构造函数,以及如何避免这种情况。

ctor不会在同一个对象上调用两次 – 而是每次都会创建一个新的View和一个新的ViewModel

默认情况下,我希望在每个平台上的每个转发导航中创建一个新的ViewModel。

默认情况下,我希望在WindowsPhone上的后退按钮期间发生这种情况 – 对于我的测试用例,这不会发生 – 但是如果出现以下情况可能会发生:

  • WindowsPhone从内存中删除了您的第一个页面(以及它的ViewModel) – 我想如果您的应用程序被逻辑删除或者您使用的是自定义RootFrame,可能会发生这种情况 – 但我不希望这种情况在默认情况下发生。
  • 你以某种方式在第一页中取消了ViewModel(DataContext)

在没有看到更多代码的情况下,我无法再猜测为什么会发生这种情况。


我个人建议你深入了解为什么你会看到在Back期间创建新的ViewModel,但是如果你只想快速修复,那么你可以看看覆盖MvvmCross中的ViewModelLocator – 请参阅MvvmCross:ShowViewModel是否总是构造新的实例?


请注意,在WindowsStore上,我希望这会发生 – 默认情况下,WindowsStore不会从内存中的Backstack中保存Pages – 但是您可以通过设置NavigationCacheMode = NavigationCacheMode.Enabled;来覆盖它NavigationCacheMode = NavigationCacheMode.Enabled; 如果你需要。