何时取消Silverlight中的事件

时间:2009-02-17 04:04:26

标签: silverlight events mvvm

单行摘要:解除在Silverlight2中UserControl的构造函数中创建的事件处理程序的最佳做法是什么?

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

我正在尝试遵循Model-View-ViewModel模式。在每种形式(从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%的情况下,它更简单。我所做的是创建两个使用相同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中的事件。我想这就是我应该解开它们的地方。

2 个答案:

答案 0 :(得分:2)

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

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

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

如果有疑问,请在调用Dispose()时实现IDisposable和unbind。

答案 1 :(得分:1)

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

但是您可以随时使用“ - =”语法明确解除绑定:

this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;

您可以实现析构函数:

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