Description
Describe the bug 🐞
I encountered this via an ObjectDisposedException
coming out of ViewForMixins.HandleViewModelActivation
. This was the result of the following sequence of events:
- A ViewModel within a DynamicData collection is disposed, after being removed from the collection.
- The
ViewModelActivator
within that ViewModel is disposed, along with it. - A View consuming this ViewModel fires the
Unloaded
event, on a future dispatcher frame. ViewModelActivator.Deactivate()
is called via disposal of a previous call to.Activate()
_deactivated.OnNext()
is called, after_deactivated
has been disposed.
I initially tried to solve this by calling .Deactivate(ignoreRefCount: true)
on the activator before disposing it, but this did not end up preventing the deactivated.OnNext()
call within .Deactivate()
. This is because I actually have 5 View consumers that are activating this ViewModel, and .Deactivate()
does not reset _refCount
to wipe these out. In other words, it's possible for ViewModelActivator.Deactivated
to fire more times than ViewModelActivator.Activated
, which is what _refCount
seems to be intended to prevent from happening.
Step to reproduce
var activator = new ViewModelActivator();
activator.Activated.Subscribe(_ => Console.WriteLine("Activated"));
activator.Deactivated.Subscribe(_ => Console.WriteLine("Deactivated"));
var activation1 = activator.Activate();
var activation2 = activator.Activate();
var activation3 = activator.Activate();
var activation4 = activator.Activate();
activator.Deactivate(ignoreRefCount: true);
activator.Dispose();
activation1.Dispose();
activation2.Dispose();
activation3.Dispose();
activation4.Dispose();
For this snippet, ObjectDisposedException
throws at the activation3.Dispose()
call.
If activator.Dispose()
is removed, then you can observe two firings of the Deactivated
event in the console, despite Activated
only firing once.
Reproduction repository
No response
Expected behavior
- A
ViewModelActivator
that has is inactive should be safe to dispose, so long as no one tries to activate it again. - Calling
ViewModelActivator.Deactivate(ignoreRefCount: true)
should render allIDisposable
s returned by previous calls to.Activate()
inert, and disposing those should not trigger an exception. - It should not be possible for the
ViewModelActivator.Deactivated
event to fire more times than `ViewModelActivator.Activated.
Screenshots 🖼️
No response
IDE
No response
Operating system
Windows
Version
10 22H2
Device
N/A
ReactiveUI Version
19.4.1
Additional information ℹ️
I would happily submit a PR to fix this, if it would be welcome.