【问题标题】:Prism View Injection Presenter and Garbage CollectionPrism View Injection Presenter 和垃圾收集
【发布时间】:2010-12-09 20:50:06
【问题描述】:

在微软的视图注入示例/文章中,他们有如下代码:

public void Initialize()
{
    this.RegisterViewsAndServices();
    EmployeesPresenter presenter = this.container.Resolve<EmployeesPresenter>();
    IRegion mainRegion = this.regionManager.Regions[RegionNames.MainRegion];
    mainRegion.Add(presenter.View);
}

http://msdn.microsoft.com/en-us/library/dd458920.aspx

这里 Presenter 被解析,它包含 IEmployeesView 类型的公共属性,用于将视图注入到区域中。解析演示者的好处是它会自动绑定到视图(通过在构造函数中获取它(通过统一))。但是你不觉得Presenter容易被垃圾回收,因为在initialize方法的作用域结束后没有任何东西引用presenter吗?

View/ViewModel 显然不会引用 Presenter,除非 VM/View 有一个由 Presenter 订阅的事件。我们可能会进入不一致的状态,即视图处于活动状态但演示者已被垃圾回收。

为了防止 Presenter 的垃圾收集,我们可能需要 ViewModel 中的 KeepAlive 属性,它只保存对 Presenter 的引用以防止其 GC,但这对我来说听起来很奇怪。在这种情况下你会做什么或会做什么?

请注意,在存在多个视图实例的情况下,向 ContainerControlledLifetimeManager 注册演示者是不可行的。此外,如果演示者(有视图)的通信模式是通过命令,并且命令恰好是 prism 的 DelegateCommands,那么它们只会保持对演示者的弱引用,这样也不会达到目的。

【问题讨论】:

  • 容器不是持有对 Presenter 的引用,这就是你使用它的原因吗?显示的代码只是获取对该 Presenter 的引用,并将其 View 粘贴到一个区域中......
  • 你所说的容器是什么?
  • Container 是 UnityContainer。通常,Resolve 本身不会将对象添加到容器中,除非您将类型注册为 ContainerControlledLifetimeManager 或 PerInstanceLifetimeManager(您可以编写),这会将其添加到容器中。
  • 有趣的是,如果没有任何东西引用 Presenter 并且视图没有公开事件,那么我可以看到 Presenter 做任何事情的唯一方法将是在内部有一个计时器可以在视图上设置数据,否则没有任何东西可以调用演示者执行任何操作。
  • 视图可以有多个实例。容器控制的生命周期管理器在那里没有意义。与视图进行通信的方式是通过命令和 prism 中的 DelegateCommands 保持对订阅者的弱引用。

标签: wpf mvvm mvp prism


【解决方案1】:

这是一个关于生命周期的复杂问题。在 Prism 文档中的这个示例中,EmployeesPresenter hooks up to an event on the EmployeesListPresenter 的实现:

public EmployeesPresenter(
            IEmployeesView view,
            IEmployeesListPresenter listPresenter,
            IEmployeesController employeeController)
        {
            this.View = view;
            this.listPresenter = listPresenter;
            this.listPresenter.EmployeeSelected += new EventHandler<DataEventArgs<BusinessEntities.Employee>>(this.OnEmployeeSelected);
            this.employeeController = employeeController;

            View.SetHeader(listPresenter.View);
        }

这将EmployeesPresenter 的生命周期与IEmployeesListPresenter 的生命周期联系起来。它像这样在容器中注册:

this.container.RegisterType<IEmployeesListPresenter, EmployeesListPresenter>();

也不是静态的,也不是 ContainerControlledLifetime。现在我们要看看EmployeesListPresenter 的实现。这是它的构造函数:

public EmployeesListPresenter(IEmployeesListView view,
            IEmployeeService employeeService)
        {
            this.View = view;
            this.View.EmployeeSelected += delegate(object sender, DataEventArgs<BusinessEntities.Employee> e)
            {
                EmployeeSelected(sender, e);
            };
            view.Model = employeeService.RetrieveEmployees();
        }

现在我们看到,EmployeesListPresenter 被绑定在 IEmployeesListView 的生命周期中。

因此,EmployeesPresenter 的生命周期与EmployeesListView 的生命周期相同,基本上只要它在控制树中。

这是一个非常令人困惑的示例。您会发现 Prism 4 样本要简单得多……如果您有选择,我建议您查看它们并可能升级到 Prism 4。

【讨论】:

  • 在某些情况下,生命周期是隐式处理的,因为演示者已经连接到视图发布的某些事件,但这并不是应用程序中可以始终如一地遵循的模式。真正的问题是,在这种情况下,每个人都使用什么样的生命周期管理策略?
  • @Hasan Khan:就我而言,我不使用 MVP……我认为这让事情变得太复杂了。我使用 MVVM 并允许 ViewModel 通过 EventAggregator 或其他机制直接通信。我不认为引入第三方除了复杂之外不会增加太多。我想你也会在 Prism 4 样本中看到这种转变。
  • @Anderson Imes - 如果有机会,请在此处查看我的问题。 stackoverflow.com/questions/15049256/… 我也使用 MVVM,但在我非常简单的 Prism 演示应用程序中无法弄清楚我有什么内存泄漏。
猜你喜欢
  • 1970-01-01
  • 2012-03-21
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多