当没有显式调用观察者上的Dispose时,我对ObservableForProperty生命周期的生命感到好奇。在这种情况下,我不太在意订阅太长等问题。
在传统的.NET中,如果您有事件,除非您取消订阅,否则可能会导致内存泄漏,原因是对象的生存期已绑定(bind)到该事件。例如,按照http://msdn.microsoft.com/en-us/magazine/cc163316.aspx的建议:
事件也可以是强大的根引用,因此可以促成强大的引用路径,从而影响对象的生存期。公共(public)语言运行时(CLR)2.0中的普通事件是事件源和监听器之间的双向强引用,因此可以使对象(源或监听器)保持事件状态,否则该对象应该已经失效。
在遇到INotifyPropertyChanged对象时浏览ReactiveUI代码库,我注意到您正在使用FromEventPattern订阅INotifyPropertyChange事件。
通过创建强引用路径,使用ObservableForProperty是否可以解决使对象保持更长时间事件的问题?
谢谢,
格伦
最佳答案
您是正确的,如果使用不当,错误地使用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);
}
因为我们已经完成了一个对象,该对象的生命周期比我们的生命周期长(即ListBox项与Window的)长,所以我们将永久持有ListBox项,直到Window消失(在您的应用程序中可能永远不会出现)。
如果仅对自己的对象使用WhenAny(即始终为
this.WhenAny
,从不someObject.WhenAny
),则可以避免绝大多数情况。有关依赖项属性的特别说明
无论如何,您都有来处理通过DependencyProperty的任何WhenAny,否则您将泄漏。因为Windows。
废话,我现在该怎么办?
ReactiveUI中添加了一个新功能来处理您确实要执行此操作的场景,称为“激活”。您可以在以下位置找到更多信息:
现在,我们可以定义“仅在屏幕上才可事件的事物”的作用域,该作用域在将View及其ViewModel从屏幕上移除(即从WPF中的Visual Tree中移除)后将立即消失。
public ItemInAListBoxViewModel(MainWindowViewModel mainWindow)
{
this.window = mainWindow;
Activator = new ViewModelActivator();
// This gets called every time the View for this VM gets put on screen
this.WhenActivated(d => {
// The 'd' is for "Dispose this when you're Deactivated"
d(this.WhenAnyValue(x => x.window.IsMinimized)
.Where(x => x == true)
.Subscribe(x => this.IsSelected = false));
});
}
为了使此工作有效,这是必须满足的条件:
ISupportsActivation
( super 简单)WhenActivated
。 听起来很难!
看起来像那样,但事实并非如此。只要记住两件事: