11

在使用FormClosing事件的时候,为什么代码e.Cancel = true;可以工作,但是new CancelEventArgs().Cancel = true;不能工作?

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;

    new CancelEventArgs().Cancel = true;
}
4

4 回答 4

23

该事件由 Winforms 管道代码引发。它可以看到自定义事件处理程序想要更改默认行为的唯一方法是通过e对象。创建一个新的 CancelEventArgs 对象没有管道可以检测到的副作用。

还有一些问题,为了外部代码的利益而引发了事件,让它知道发生了什么并给它一个改变行为的选项。这里没有外部代码,事件处理程序实际上是引发事件的同一类的一部分。换句话说,表单正在监听它自己的事件。有一个更好的方法来处理这个问题,你重写引发事件的方法。像这样:

    protected override void OnFormClosing(FormClosingEventArgs e) {
        e.Cancel = true;
        base.OnFormClosing(e);
    }

现在外部代码可以覆盖默认行为,在 OnXxxx 方法运行后引发事件。而且您可以选择,如果您不希望外部代码覆盖该行为,只需交换两个语句即可。

于 2011-02-28T13:55:50.247 回答
15

我认为代码完全按照它所说的去做;缺少的是对它的字面阅读。

当您为 分配新值时e.Cancel,您正在修改e作为参数提供给函数的 。在事件处理程序函数完成后,这个FormClosingEventArgs实例,包括在事件处理程序中对其所做的任何更改,将可用于调用事件处理程序的任何代码。在这种情况下,几乎可以肯定是微软编写的 Winforms 代码。

另一方面,当您该事件处理程序中创建该类型的新实例FormClosingEventArgs并对其执行某些操作时,没有什么可以将该信息提供回调用者;你需要一些明确的东西。由于调用者正在查看事件处理程序完成后传入的参数的值,因此您需要以某种方式将e调用者看到的内容替换为新创建的实例。在其他情况下,可能会提供这样的结果作为返回值。

通常,new T()对于某些 type T,结果是 type 的一个实例Tnew T()因此,您可以像处理类型的非空变量一样处理表达式的结果T。在您的特定情况下,您正在为类型上的属性分配一个值T(特别是,由此创建的该类型的实例)。(有构造函数失败的特殊情况,但我们暂时不要去那里;对于简单的类型,这几乎意味着您处于如此可怕的困境中,以至于您的程序在任何情况下都不太可能继续运行。 )

这里重要的是,如果您不在任何地方分配表达式new T() 本身的结果,那么一旦语句完成,新创建的实例就会被丢弃(从技术上讲,变得不可访问)。然后在稍后的某个时间点,.NET 垃圾收集器启动并实际回收分配的内存。这与在一个函数中分配变量、从另一个函数调用该函数并尝试访问从第二个函数分配的变量而不做任何事情将变量从第一个函数转移到第二个函数并没有什么不同,除了这里只涉及一项功能。

在事件处理程序中执行类似于您的第二行代码的操作将是相当不寻常的,但如果调用构造函数具有您希望使用的某些副作用(例如触发延迟加载),原则上可能是有效的

于 2011-02-28T13:24:59.887 回答
6

这段代码肯定有效,只需检查一下

protected override void OnFormClosing(FormClosingEventArgs e)
        {            
            base.OnFormClosing(e);
            if (PreClosingConfirmation() == System.Windows.Forms.DialogResult.Yes)
            {
                Dispose(true);
                Application.Exit();
            }
            else
            {
                e.Cancel = true;
            }
        }

        private DialogResult PreClosingConfirmation()
        {
            DialogResult res = System.Windows.Forms.MessageBox.Show(" Do you want to quit?          ", "Quit...", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            return res;
        }

快乐编码

于 2013-02-21T07:54:30.823 回答
3

这是因为CancelEventArgs是在您的代码中传递给事件处理程序的对象引用。幕后代码FormClosing使用CancelEventArgs对象引发,所有事件处理程序都接收相同的对象。轮到所有处理程序后,幕后代码会检查CancelEventArgs它发送的对象以查看其Cancel属性是否设置为true. 如果是,它什么也不做,FormClose事件链停止。如果CancelfalseCancelEventArgs默认值),意味着它没有被设置为Cancel事件链,幕后代码继续执行,然后引发FormClosed事件。

您可以在 MSDN 上的 Form.FormClosing Event中阅读更多内容。

Forms所有的 -ing 事件之后,通常都会跟着一个 -ed 事件。-ing 事件通常具有CancelEventArgs,可以将其Cancel属性设置true为阻止 -ed 事件发生。

于 2013-05-03T17:36:52.160 回答