MvvmCross:在 ViewModel 中引发事件的最佳方式?

MvvmCross: Best way to raise event in ViewModel?

我目前有一个视图(Android 片段)和一个对应的 ViewModel。我现在想在视图可以订阅的视图模型中引发一个事件。

存档的最佳方式是什么?我听说常规 C# 事件(委托)会导致内存泄漏?这是WeakSubscribe函数的原因吗?如何绑定到事件?

如果您订阅临时对象中的事件并且在释放临时对象之前不取消订阅,则可能会造成泄漏。在您的情况下,这种情况的可能性很小,因为视图模型很可能只会创建一次。

由于您使用的是 mvvm,事件的替代方法是 Messengers,您可以在 MvvmLight 或 MvvmCross 等流行的 mvvm 框架中找到它。这为您提供了真正解耦的事件,因为您只需要知道消息的格式而无需了解有关发件人的任何信息(在您的情况下是 ViewModel)。使用 Messenger,您只需订阅一种消息类型,发件人可以在应用程序的任何位置。

为了防止您的视图内存泄漏,您订阅的每个事件都需要取消订阅,无论是使用 WeakSubscribe 还是照常订阅事件。

一个常见的场景是订阅:

  • Android OnResume()
  • iOS ViewWillAppear()

然后处理订阅:

  • Android OnPause()
  • iOS ViewWillDisappear()

弱订阅

如果你想"listen" for ViewModel 属性改变,WeakSubscribe就派上用场了:

private IDisposable _selectedItemToken;

_selectedItemToken = ViewModel.WeakSubscribe(() => 
    ViewModel.SelectedItem, (sender, eventArgs) => {
        // do something
});

Just notice that WeakSubscribe() returns an MvxWeakEventSubscription that is also IDisposable. You need to save a reference to that subscription in your view and dispose it when thew view is no longer needed. There are two reasons to keep that reference:

  1. You can dispose it later
  2. If you don´t keep it, your lambda event handler may not always work

稍后...

_selectedItemToken?.Dispose();

正常事件订阅

如果您只需要在您的 ViewModel 中订阅另一种事件(而不是 属性 更改),您实际上并不需要 WeakSubscribe。您可以只向 ViewModel 添加一个事件侦听器,就像您对任何对象所做的那样。

ViewModel.AnEvent += YourDelegate;

稍后...

ViewModel.AnEvent -= YourDelegate;

Don´t forget the last step. That will prevent memory leaks. As I said, Android OnPause() and iOS ViewWillDisappear() are good places to do it.

这样,当视图被释放时,您的 ViewModel 就不会卡在内存中,因此您的视图可以正确地被垃圾回收。