【问题标题】:When to unhook events in Silverlight何时取消挂钩 Silverlight 中的事件
【发布时间】:2009-02-17 04:04:25
【问题描述】:

一行总结:在 Silverlight2 的 UserControl 的构造函数中创建的取消挂钩事件处理程序的最佳实践是什么?

背景: 我目前正在 Silverlight2 中构建业务线应用程序。由于 Silverlight 是一个浏览器插件,因此没有窗口的概念 - 一切都在 UserControls 中完成。我在应用程序中处理不同“表单”的方式是拥有一个包含 Viewbox 的顶级用户控件。为了显示不同的表单,我将 Viewbox 的 Child 属性设置为不同的 UserControl。我的应用程序有一个单独的 PageManager 类,调用它来打开和关闭表单。表单 (UserControls) 存储在堆栈中。打开一个表单将它放在堆栈的顶部,关闭它会将它从堆栈中移除并显示它下面的一个。

我正在尝试遵循模型-视图-视图模型模式。在每个表单(从 UserControl 派生)中,我都有一个 ViewModel 来管理 View 的所有数据。 ViewModel 公开事件,以便在加载和保存等操作完成时通知 UI。

在我的表单中,在获得 ViewModel 之后,我订阅了构造函数中的事件

public partial class MyPage : UserControl
{

    public MyViewModel ViewModel{get; set;}

    // other constructors, which create the viewmodel and call the constructor below.

    public MyPage(MyViewModel viewModel)
    {
        InitializeComponent();
        ViewModel = viewModel;
        this.LayoutRoot.DataContext = this.ViewModel;

        // subscribe to event so we can do stuff
        this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted);
    }

我的问题是:既然我已经订阅了这个事件,我什么时候删除处理程序?我是创建一个析构函数并在那里执行它,还是创建一个先有鸡还是先有蛋的情况,即垃圾收集器在所有引用(即:事件处理程序)都消失之前不会销毁对象?我是否创建了一个表单必须实现的接口,该接口指定了一个在 PageManager 关闭表单时调用的 UnhookEvents 函数?

编辑:感谢您的回复。 ViewModel持续时间长于表单(UserControl)的情况呢?我的应用程序的一部分允许用户创建相当复杂的结构,但在 95% 的情况下它要简单得多。我所做的是创建 2 个使用相同 ViewModel 的表单。用户可以开始填写简单的表单,然后切换到高级模式,这将创建一个新表单,并将 ViewModel 传递给它。

在简单的设置表单中:

    private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session");
    }

在高级设置表单中:

    private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session");
    }

在 PageManager.Close 之后,唯一引用表单的是 ViewModel 中的事件。我想这就是我应该解开它们的地方。

【问题讨论】:

    标签: silverlight events mvvm


    【解决方案1】:

    在这种情况下,不需要 C# 程序员通常称为终结器的析构函数。假设 ViewModel_LoadCompleted 是一个成员函数,它包含一个指向“this”的指针,您将其提供给完全包含在“this”中的 ViewModel 对象。垃圾收集器应该智能地忽略这一点。

    在这种情况下,正确的做法是不要浪费时间解绑它们。

    一般来说,当您将“this”(显式或隐式)传递给某个对象,该对象将持有该引用的时间超过“this”的预期生命周期时,您需要取消绑定事件处理程序。例如,如果您在父控件的事件上设置处理程序。现在,父级通过处理程序及其子控件集合对您进行了引用。在这种情况下,您应该在从父级中移除时解除绑定。

    如有疑问,请在对 Dispose() 的调用中实现 IDisposable 并取消绑定。

    【讨论】:

    • 如果我的 ViewModel 持续时间比 UserControl 长怎么办? (我将编辑问题以说明如何)
    • 如果你的模型持续时间比用户控件长,那么你也不必担心解除绑定。该模型不应引用控件。当控件超出范围时,它将被垃圾收集并且不再指向模型。
    • 怎么样?支持事件的 MulticastDelegate 持有对处理事件的对象的强引用。
    • 我做了一个(有时是无效的)假设,即 ViewModel 与 UserControl 有 1:1 的对应关系。如果我的假设成立,那么我的评论是有道理的。如果我的假设没有,那么它与绑定到父控件是一样的,你必须显式地取消绑定。
    【解决方案2】:

    当垃圾收集器通过您的对象时,事件会自动解除绑定。

    但您可以随时使用“-=”语法显式取消绑定:

    this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
    

    你可以实现析构函数:

    ~MyPage
    {
        this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多