I am curious about the life time of ObservableForProperty lifetime when not explicitly calling the Dispose on the Observer. I don't really care in this scenario about getting subscriptions for too long etc.
In traditional .NET if you have events unless you unsubscribed it could potentially lead to memory leaks due to the fact your object lifetime is bound to the event. eg as suggested in http://msdn.microsoft.com/en-us/magazine/cc163316.aspx :
Events can also be strong root references and as such can contribute to the strong reference path and thus affect the lifetime of an object. Ordinary events in the common language runtime (CLR) 2.0 are bidirectional strong references between the event source and the listener and as such can keep an object (either source or listener) alive that otherwise should be dead already.
Looking through the ReactiveUI code base when encountering a INotifyPropertyChanged object, I notice you are using FromEventPattern subscribing to INotifyPropertyChange event.
Does using ObservableForProperty get around this problem of keeping object's alive for longer by creating the strong reference path?
Thanks, Glenn
You are correct, using WhenAny / ObservableForProperty incorrectly can cause your application to leak memory if you are not careful. Consider the following code:
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);
}
Because we've WhenAny'd through an object whose lifetime is longer than ours (i.e. the ListBox item vs the Window), we're holding ListBox items forever until the Window goes away (which may be never in your app).
You will avoid the vast majority of these cases if you only WhenAny on your own object (i.e. always this.WhenAny
, never someObject.WhenAny
).
No matter what, you have to Dispose of any WhenAny that goes through a DependencyProperty, or else you leak. Because Windows.
A new feature was added to ReactiveUI to handle the scenario where you do want to do this though, called "Activation". You can find more info at:
We can now define a Scope of "things that should only be active when On Screen", that will go away immediately after a View and its ViewModel are removed from the screen (i.e. removed from the Visual Tree in WPF).
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));
});
}
For this to work, here's what needs to be true:
ISupportsActivation
(super easy)WhenActivated
too.It looks that way, but it's totally not. Just remember two things:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With