MVVMLight Messenger.Unregister - 我应该解除注册吗?如何解除注册?

3
我看过'Messenger和引用'讨论,但我正在写一个新主题,因为我的问题不是技术性的,我不想在那里离题。
我遇到了一个疑问-我是否需要编写cleanup()/RequestCleanup()方法的实现来注销先前在我的视图模型类中注册的Messenger?我担心未来会出现内存泄漏问题。我认为我找到的文档对我来说不够清晰。
Messenger.Register的描述是:“……注册收件人不会创建对其的硬引用,因此如果删除此收件人,则不会导致内存泄漏。” 1)这是否意味着我不必担心它并实现开发以下解决方案?
另一方面,在GalaSoft.MvvmLight.ViewModelBase抽象类的代码中,我们可以找到关于Cleanup()方法的简短信息:
    //
    // Summary:
    //     Unregisters this instance from the Messenger class.
    //     To cleanup additional resources, override this method, clean up and then
    //     call base.Cleanup().
    public virtual void Cleanup();

所以2)仅调用Cleanup就足以从Messenger中注销类实例吗?

3)还是说我必须在Cleanup方法的主体中调用?

4)在Unregister(Object)文档中,我们读到“完全取消注册消息接收者” - “完全”是什么意思?

如果我的帖子似乎引用了上下文之外的内容,我非常抱歉,我想指出我更感兴趣的内容。

编辑1: 你好Joel,谢谢回复。我有几个问题:
1)我使用了你的代码。CustomerMasterViewModel中定义了覆盖void Cleanup()。在哪里调用它?在这种情况下应该声明析构函数,还是ViewModelBase有一个自动机制来调用Cleanup()?

2)在我的项目中,我有另一个来自不同工具包的基类,因此我的VM无法同时继承两者。如何组织您的代码以通过仅实现ICleanup接口获得相同的效果?

public class CustomerMasterViewModel : SomeBaseClass, ICleanup
{
    public CustomerMasterViewModel()
    {
        Messenger.Default.Register<Message>(this, this.MessageReceived);
    }

    #region messages

    private void MessageReceived(Message obj)
    {
        //do something
    }

    #endregion

    #region helper methods

    public override void Cleanup()
    {
        //base.Cleanup();//there's no implementaction in an interface
        ViewModelLocator.Cleanup();
    }

    #endregion
}
1个回答

5
您必须在每个视图模型中调用GalaSoft.MvvmLight.ViewModelBase中的Cleanup()方法,以释放您不再需要的视图模型。
例如:假设您的应用程序具有带有不同选项卡的选项卡控件。每个选项卡都显示一个具有专用ViewModel的UserControl。用户可以关闭选项卡,这会导致底层ViewModel变得过时。
现在您要做的是清理ViewModel,调用GalaSoft.MvvmLight.ViewModelBase中的Cleanup()方法。这将注销所有已注册的消息。如果没有其他引用,则GarbageCollector将处理您的viewmodel。
假设您使用的是MVVM Light Framework附带的ViewModelLocator,那么您还没有完成,因为至少ViewModelLocator本身引用了您的viewmodel!因此,垃圾回收器无法完成您的viewmodel。
但它还有另一个副作用。当用户重新打开选项卡时(假设用户能够这样做),UserControl会再次加载,并且ViewModelLocator将为您提供相同的ViewModel实例。唯一的区别是没有注册的消息,因为您通过调用CleanUp()方法将它们清除了。
您需要的是ViewModel的新实例。要实现这一点,您也必须清理ViewModelLocator!
您必须逐个注销它们(Unregister<CustomerMasterViewModel>()),或者只需调用Reset(),它将注销所有视图模型。
然后就不应该再有对您的viewmodel的引用了,垃圾回收器最终可以处理它。
以下是一个示例:
public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            SimpleIoc.Default.Register<CustomerMasterViewModel>();
        }

        public CustomerMasterViewModel CustomerMasterViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<CustomerMasterViewModel>();
            }
        }

        public static void Cleanup()
        {
            SimpleIoc.Default.Reset();
            //Don't forget to register them if the user attempts to open the new. 
            //The viewmodel initialization is lazy by default so this comes at no costs.
            SimpleIoc.Default.Register<CustomerMasterViewModel>();
        }
    }

ViewModel

public class CustomerMasterViewModel : ViewModelBase
{
    public CustomerMasterViewModel()
    {
        Messenger.Default.Register<Message>(this, this.MessageReceived);
    }

    #region messages

    private void MessageReceived(Message obj)
    {
        //do something
    }

    #endregion

    #region helper methods

    public override void Cleanup()
    {
        base.Cleanup();
        ViewModelLocator.Cleanup();
    }

    #endregion
}

简而言之:
1) 据我所了解,完成后需要清理。
2) 是的,在GalaSoft.MvvmLight.ViewModelBase中调用Cleanup()方法将取消注册此ViewModel的所有消息。
3) 不是,见上面。
4) 完全意味着它将注销所有已注册的消息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接