你是正确的,如果使用WhenAny / ObservableForProperty不当,可能会导致应用程序泄漏内存,如果不小心的话。考虑以下代码:
public ItemInAListBoxViewModel(MainWindowViewModel mainWindow)
{
this.window = mainWindow;
// Reset the "selected" when the user minimizes
this.WhenAnyValue(x => x.window.IsMinimized)
.Where(x => x == true)
.Subscribe(x => this.IsSelected = false);
}
因为我们已经通过一个生命周期比我们更长的对象进行了WhenAny(即ListBox项目与Window),所以我们会一直持有ListBox项目,直到Window消失(在您的应用程序中可能永远不会消失)。
如果您只对自己的对象进行WhenAny(即始终使用this.WhenAny
,而不是someObject.WhenAny
),则可以避免绝大多数这些情况。
关于依赖属性的特别说明
无论如何,您必须Dispose任何通过DependencyProperty进行的WhenAny,否则就会泄漏。因为Windows。
该怎么办?
ReactiveUI添加了一个新功能来处理您确实希望这样做的情况,称为“Activation”。您可以在以下链接中找到更多信息:
我们现在可以定义一个范围,即“仅在屏幕上活动时应处于活动状态的事物”,该范围将在视图及其视图模型从屏幕中移除(即从WPF的可视树中移除)后立即消失。
public ItemInAListBoxViewModel(MainWindowViewModel mainWindow)
{
this.window = mainWindow;
Activator = new ViewModelActivator();
this.WhenActivated(d => {
d(this.WhenAnyValue(x => x.window.IsMinimized)
.Where(x => x == true)
.Subscribe(x => this.IsSelected = false));
});
}
为了让它工作,需要满足以下条件:
- 您的VieWModel需要实现
ISupportsActivation
(非常简单)
- 与您的ViewModel相关联的View也需要调用
WhenActivated
。
这听起来超级难!
看起来是这样,但实际上并不是。只需记住两件事:
- 不要通过永久存在的对象进行WhenAny操作,除非您也永久存在
- 如果必须这样做,请使用WhenActivated。