Caliburn Micro EventAggregator subscribe/unsubscribe multiple instances of same ViewModel

1.1k views Asked by At

I recently found out that my Handle() method was called multiple times after a single publish... and discovered that deactivated and closed ViewModel instances were actually not disposed of and kept receiving messages ! I'm looking for a way to either properly dispose of obsolete viewmodels or simply remove them from EventAggregator subscription.

My shell is a

Conductor<T>.Collection.OneActive, IScreenEx where T : class, IScreenEx

The conducted items are registered with SimpleContainer as follow:

container.PerRequest<ILinkageMovements, LinkageGraphViewModel>();

and activated like this:

    public X SwitchToNamed<X>(String key) where X : T
    {
        var existing = Items.FirstOrDefault(y => y.GetType() == typeof(X) && y.UniqueKey == key);

        if (existing == null)
            existing = Items.FirstOrDefault(x => x.GetType().GetInterfaces().Contains(typeof(X)) && x.UniqueKey == key);

        if (existing != null)
        {
            ChangeActiveItem(existing, false);
            return (X)existing;
        }
        else
        {
            X vm = container.GetInstance<X>();
            vm.UniqueKey = key;
            ActivateItem(vm);
            return vm;
        }
    }

And the ViewModel is constructed this way:

    public LinkageGraphViewModel
        (
            Caliburn.Micro.SimpleContainer container,
            Caliburn.Micro.IEventAggregator eventAggregator,
            IDialogManager dialogs,
            IDataService dataService,
            IReferentialData refData
        )
        : base(container, eventAggregator, dialogs, dataService, refData)
    {
        DisplayName = Strings.Movements;
    }

Finally the very base class constructor is:

    public BaseConductor(SimpleContainer container, IEventAggregator eventAggregator, IDialogManager dialogs)
    {
        this.container = container;
        this.eventAggregator = eventAggregator;
        this.eventAggregator.Subscribe(this);
        this.Dialogs = dialogs;
    }

Please help.

1

There are 1 answers

0
Alexander Balabin On

There is an Unsubscribe method on IEventAggregator interface.

The answer the question about when it's a good time to call it depends on your architecture - the code you posted does not explain when your view models are not needed anymore - they might stay in Items forever.

Normally you'd subscribe in OnActivate and unsubscribe in OnDeactivate however your code subscribes in the constructor so I guess you might want inactive models to be subscribed so CanClose might be another candidate.