ViewModel'的构造函数在导航时再次被调用,因此再次订阅了信使订阅
本文关键字:信使 调用 构造函数 导航 ViewModel | 更新日期: 2023-09-27 18:16:43
我正在使用MvvmCross
框架构建一个跨平台的移动应用程序。
因为我想在ViewModels之间共享信息,我在ViewModel的构造函数中注册通知,使用内置的MvxMessenger
。
让我们假设一个名为ShowAdsMsg
的消息,然后ViewModel看起来如下:
public class AdsViewModel : BaseLookersViewModel, IAdsViewModel
{
private MvxSubscriptionToken _showAdsMsgToken;
public AdsViewModel()
{
_showAdsMsgToken = MvxMessenger.Subscribe<ShowAdsMsg>(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<AdsViewModel>( );
}
我现在能够导航到ViewModel,并且所有的通知都被成功捕获。
然而…
当我按下设备上的BACK按钮并重新导航到相同的ViewModel时,
构造函数再次被调用,因此消息订阅再次发生。
结果,当消息到达时,onShowAdsNavigation()
处理程序被触发两次!
我发现了这个类似的帖子,讨论如何正确处理ViewModel的问题,
但是它没有直接解决我的问题。
我需要的是一个解决方案。它可以是下列任意一种:
- 关于如何在ViewModel的actor上不订阅消息的想法。
- 关于如何以及何时正确处置ViewModel的指导。
- 解释构造函数为什么会被再次调用,以及如何避免这种情况。
- 一个完全不同的ViewModel信息传递方法。
提前感谢您的帮助!
编辑:我找到了这个SO答案,它基本上回答了上面列表中的第3个问题。但是,我在想我应该采取什么方法来解决信使的问题。
另一个编辑:我验证了同样的行为存在于MvvmCross教程N-05-MultiPage。我只是在SecondViewModel中添加了一个actor,并在每次BACK+ renavate之后在其中命中一个断点。
解释构造函数为什么会被再次调用,以及如何避免这种情况。
ctor
不会在同一个对象上被调用两次——相反,可能发生的情况是每次都创建一个新的View
和一个新的ViewModel
。
默认情况下,我将期望在每个平台上的每个正向导航上创建一个新的ViewModel。
默认情况下,我将**不期望在WindowsPhone的后退按钮期间发生这种情况-它不会在我的测试用例中发生-但它可能发生,如果:
- WindowsPhone从内存中删除你的第一页(和它的ViewModel) -我想这可能会发生,如果你的应用程序是墓碑,或者如果你使用自定义RootFrame -但我不希望这在默认情况下发生。
- 你以某种方式在你的第一页null ViewModel (DataContext)
如果没有看到更多的代码,我无法猜测更多的为什么会发生这种情况。
我个人建议你更深入地了解为什么你在Back期间看到新的ViewModels创建,但如果你只是想快速修复,那么你可以看看在MvvmCross中重写ViewModelLocator -参见MvvmCross: ShowViewModel总是构造新的实例吗?
请注意,在WindowsStore上,我希望发生这种情况- WindowsStore默认情况下不会在内存中保存来自backstack的页面-但是如果需要,您可以通过设置NavigationCacheMode = NavigationCacheMode.Enabled;
来覆盖这一点。