Question

I'm using the MVP pattern to create view modules that are loaded into a Shell via a factory:

public class ViewModuleFactory : IViewModuleFactory
{
  private readonly IEventAggregator Events;

  public ViewModuleFactory(IEventAggregator Events)
  {
    this.Events = Events;
  }

  public Control CreateModule()
  {
    var view = new View();
    var presenter = new Presenter(Events, view);

    return view;
  }
}

After the module is loaded in the shell, I fire an event via the Prism Event Aggregator to populate the module. I was finding, however, that it would never populate. My conclusion is that the presenter (which handles the event) is getting garbage collected and thus the published event falls on deaf ears. I've confirmed this by creating a destructor and breakpointing it.

I can identify possible solutions, but they come with caveats:

1) I thought of setting KeepSubscriberReferenceAlive to true, but another SO answer states this should be a rare occurrence.

2) I could give the view a reference to its presenter, but I'm in the camp that thinks the view should be wholly dumb and possess no reference to the presenter.

3) I could give the ViewModuleFactory a field reference to the Presenter. The factory stays alive for the life of the program and thus the presenter reference is maintained, but I feel that might open another can of worms entirely.

What is really strange is that I have another module in the ViewFactory that loads exactly the same way, but somehow that presenter is not getting finalized like this one is.

Any help would be appreciated.

No correct solution

OTHER TIPS

I have experienced similar issues when using the model-view-presenter pattern and in my opinion option 2 is the simplest method.

You can do this without the view 'knowing' about the concrete presenter by having all your views implement the following basic interface:

public interface IView
{
    object Presenter { set; }
}

Seeing as you are using WinForms you can have a base class that implements the IView interface and stores the presenter object in the Tag property.

public abstract class ViewBase : UserControl, IView
{
    public object Presenter
    {
        set { this.Tag = value; }
    }
}

Your presenter base class can then be updated to set the IView.Presenter property and pass itself to the view to ensure the reference is kept alive e.g.

public class Presenter
{
    public Presenter(View view)
    {
        view.Presenter = this;
    }
}

Alternatively, your view class could just directly hold a reference to the presenter object like this:

public abstract class ViewBase : UserControl, IView
{
    private object _presenter;

    public object Presenter
    {
        set { this._presenter = value; }
    }
}

Although your view classes now have a reference to a presenter, they do not know the actual concrete type of the presenter and as long as the field is private, subclasses cannot actually retrieve and use the presenter in any way so this merely becomes an implementation detail of your framework that is used to tie the lifetime of the presenter to the lifetime of it's associated view.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top