导航时再次调用ViewModel的构造函数,因此再次订阅了Messenger订阅 [英] ViewModel's constructor is being called again on navigation, and so messenger subscriptions are being subscribed again

查看:55
本文介绍了导航时再次调用ViewModel的构造函数,因此再次订阅了Messenger订阅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am building a cross-platform mobile application using MvvmCross framework.

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

Since I would like to share information between ViewModels, I am registering notifications inside the ViewModel's constructor, using the built in MvxMessenger.
Let's assume a message named ShowAdsMsg, and then the ViewModel looks as follows:

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问题:
MainViewModel执行到ViewModel的实际导航.
由于在导航本身的瞬间,AdsViewModel尚不存在,因此从MainViewModel发布的消息无法到达它.
因此,我的想法是天真地记住"消息并在新的ViewModel准备就绪时发布.
因此,现在MainViewModel中的导航调用看起来像这样:

About the MyMessenger thing:
The actual navigation to the ViewModel is performed from MainViewModel.
Since that at the very moment of the navigation itself the AdsViewModel does not exist yet, messages published from the MainViewModel cannot reach it.
So, my idea was to naively "remember" the message and publish it when the new ViewModel is ready.
So now the navigation call from the MainViewModel looks like that:

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

我现在可以导航到ViewModel,并且成功捕获了所有通知.

I am now able to navigate to the ViewModel, and all the notifications are successfully caught.

但是...
当我按设备上的BACK按钮并重新导航到相同的ViewModel时,
构造函数被再次调用,因此消息订阅再次发生.
结果,当消息到达时,onShowAdsNavigation()处理程序将被触发两次!

However...
When I press the BACK button on the device and re-navigate to the same ViewModel,
The constructor is being called again, and so the message subscription re-occur.
As a result, when a message arrives the onShowAdsNavigation() handler is being fired twice!

我发现了类似帖子,讨论了如何正确处理ViewModel,
但这并不能直接解决我的问题.

I found this similar post, discussing the question of how to properly dispose a ViewModel,
but it does not contain a direct solution to my problem.

我需要一个解决方案.可以是以下之一:

What I need is a solution. It can be either one of the following:

  1. 说明如何在ViewModel的ctor上不订阅消息.
  2. 有关如何以及何时正确处理ViewModel的指南.
  3. 说明为何再次调用构造函数以及如何避免这种情况.
  4. 一种完全不同的ViewModel信息消息传递方法.

预先感谢您的帮助!

我找到了 SO答案,该答案基本上回答了上面的清单. 不过,我仍想知道在处理Messenger问题时应该采取什么方法.

I found this SO Answer, which basically answers item number 3 in the list above. Still, I am wondering what approach should I take regarding the messenger issue.

另一个 我验证了MvvmCross教程 N-05-MultiPage .我只是在SecondViewModel中添加了一个ctor,并且在每次BACK + Renavigate之后都在其中击中了一个断点.

Another I verified that the same behavior exists with MvvmCross tutorial N-05-MultiPage. I simply added a ctor to SecondViewModel, and I hit a breakpoint inside it after each BACK+Renavigate.

推荐答案

说明为何再次调用构造函数以及如何避免这种情况.

Explanation on why the constructor is being called again, and how to avoid that.

在同一对象上没有两次调用ctor-而是可能每次创建一个新的View和一个新的ViewModel.

The ctor is not called twice on the same object - instead what might happen is that a new View and a new ViewModel are created each time.

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

By default I would expect a new ViewModel to be created on every forwards navigation on every platform.

默认情况下,我不会期望这会在WindowsPhone的后退按钮期间发生-在我的测试用例中不会发生这种情况-但在以下情况下可能会发生:

By default I would **not expect this to happen during a back button on WindowsPhone - it doesn't happen here for my test cases - but it could happen if:

  • WindowsPhone从内存中删除了您的第一个Page(它是ViewModel)-我猜这可能发生在您的应用程序被逻辑删除或使用自定义RootFrame的情况下-但我不希望默认情况下会发生这种情况.
  • 您以某种方式在第一页中将ViewModel(DataContext)清空了

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

Without seeing more of your code I can't guess any more about why this might happen.

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

I'd personally recommend you look deeper at why you are seeing new ViewModels created during Back, but if you just want a quick fix, then you could look at overriding the ViewModelLocator within MvvmCross - see MvvmCross: Does ShowViewModel always construct new instances?

请注意,在WindowsStore上,我希望这种情况会发生-WindowsStore默认情况下不会将后退页面保存在内存中-但您可以根据需要设置NavigationCacheMode = NavigationCacheMode.Enabled;来覆盖它.

Note that on WindowsStore, I would expect this to happen - WindowsStore doesn't hold Pages from the backstack in memory by default - but you can overriding this by setting NavigationCacheMode = NavigationCacheMode.Enabled; if you need to.

这篇关于导航时再次调用ViewModel的构造函数,因此再次订阅了Messenger订阅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆