【问题标题】:How to avoid raising an event to a closed form?如何避免将事件提升为封闭形式?
【发布时间】:2011-02-10 04:12:41
【问题描述】:

我在处理事件被提升为封闭形式并希望获得一些帮助的情况时遇到了问题。

场景(参考以下代码):

  1. Form1 打开 Form2
  2. Form1 订阅了Form2 上的一个事件(我们称这个事件为FormAction
  3. Form1 已关闭,Form2 保持打开状态
  4. Form2 引发 FormAction 事件

Form1.form2_FormAction 中,为什么this 返回对Form1 的引用而button1.Parent 返回null?他们不应该都返回相同的引用吗?

如果我们省略第 3 步,thisbutton1.Parent 都会返回相同的引用。

这是我正在使用的代码...

Form1:

public partial class Form1 : Form
{
    public Form1 ()
    {
        InitializeComponent();
    }

    private void button1_Click ( object sender , EventArgs e )
    {
        // Create instance of Form2 and subscribe to the FormAction event
        var form2 = new Form2();
        form2.FormAction += form2_FormAction;
        form2.Show();
    }

    private void form2_FormAction ( object o )
    {
        // Always returns reference to Form1
        var form = this;

        // If Form1 is open, button1.Parent is equal to form/this
        // If Form1 is closed, button1.Parent is null
        var parent = button1.Parent;
    }
}

Form2:

public partial class Form2 : Form
{
    public Form2 ()
    {
        InitializeComponent();
    }

    public delegate void FormActionHandler ( object o );
    public event FormActionHandler FormAction = delegate { };

    private void button1_Click ( object sender , EventArgs e )
    {
        FormAction( "Button clicked." );
    }
}

理想情况下,我希望避免将事件引发到已关闭/已处理的表单(我不确定这是否可能),或者在调用者中找到一种干净的处理方式(在本例中为 Form1)。

感谢任何帮助。

【问题讨论】:

    标签: c# winforms events delegates


    【解决方案1】:

    当您关闭form1 时,您应该取消订阅该事件:

    form2.FormAction -= form2_FormAction;
    

    【讨论】:

    • form2 的范围不允许这样做。
    • @Steve - 那么你必须扩展form2 的范围才能做到这一点。除非您取消订阅该事件,否则您的处理程序将被调用。
    • 为什么不能更改范围?是否希望能够打开多个 Form2?
    • 更改范围是一种选择,我知道如何处理这种情况。我只是问我描述的场景(考虑的范围)是否可以处理。
    • @Steve Dignan - 根据传递给事件处理程序的参数,您可以检查表单是否已关闭并在处理程序开始时取消订阅事件。但这很丑陋。跟上表单订阅的事件,并在表单关闭时删除订阅是正确的方法。
    【解决方案2】:

    一个简单的解决方案是使用带有所有者的覆盖来显示您的 Form2 实例:

    form2.Show(this);
    

    这将确保 form2 在 form1 关闭时关闭。在多表单应用程序中,这通常是一种很好的做法,这样您就不会有任何无主表单漂浮在周围。

    更新:事件模型只是处理表单之间通信的一种方式。在您的情况下,它并不适合,因为接收事件的表单可以关闭,而引发事件的表单不会意识到它。

    另一种方法是使用包含 Form1 实例作为参数的构造函数编写 Form2(将保存为表单级成员,如 _Receiver 或其他东西)。 Form2 不会引发事件,而是会在检查 _Receiver 是否已被释放后调用 Form1 中定义的方法:

    if (!_Receiver.IsDisposed)
    {
        _Receiver.SomeMethod("some method");
    }
    

    如果您的 Form1 实例还在,它的方法将被调用;如果它被关闭和处置,它的方法将不会被调用。由于 Form2 仍然存在,您还可以将 _Receiver 设为公共属性,并随时将其“所有者”设置为其他 Form1。

    【讨论】:

    • 应用程序的设计允许子表单在父表单关闭后保持打开状态。不幸的是,我无法更改设计。
    猜你喜欢
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    相关资源
    最近更新 更多