保持演示者引用存活,而不引用它控制的视图

时间:2014-02-13 19:15:56

标签: c# winforms events garbage-collection mvp

我使用MVP模式创建通过工厂加载到Shell中的视图模块:

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;
  }
}

在shell中加载模块后,我通过Prism Event Aggregator触发事件来填充模块。然而,我发现它永远不会填充。我的结论是主持人(处理事件)正在收集垃圾,因此发布的事件被置若罔闻。我通过创建一个析构函数并对其进行破坏来证实了这一点。

我可以找出可能的解决方案,但它们带有警告:

1)我想过将KeepSubscriberReferenceAlive设为true,但another SO answer states this should be a rare occurrence

2)我可以给view presenter提及view,但我在营地认为ViewModuleFactory应该完全愚蠢而且没有提及主持人。

3)我可以为Presenter提供ViewFactory字段引用。工厂在程序的生命周期内保持活力,因此主持人参考被保留,但我觉得可能完全打开另一种蠕虫。

什么是真的奇怪的是我在{{1}}中有另一个模块以完全相同的方式加载,但不知何故,演示者没有最终确定如此。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:1)

在使用模型 - 视图 - 演示者模式时我遇到过类似的问题,在我看来,选项2是最简单的方法。

你可以在没有视图的情况下做到这一点并且知道'通过让所有视图实现以下基本界面来了解具体的演示者:

public interface IView
{
    object Presenter { set; }
}

当您使用WinForms时,您可以拥有一个实现IView接口的基类,并将presenter对象存储在Tag属性中。

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

然后可以更新您的演示者基类以设置IView.Presenter属性并将其自身传递给视图以确保引用保持活动,例如。

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

或者,您的视图类可以直接保存对presenter对象的引用,如下所示:

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

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

虽然你的视图类现在有一个对演示者的引用,但是他们不知道演示者的实际具体类型,只要该字段是私有的,子类就不能以任何方式实际检索和使用演示者,所以这只会变成框架的实现细节,用于将演示者的生命周期与其关联视图的生命周期联系起来。