"e.Cancel" в форме закрытия мероприятия - PullRequest
11 голосов
/ 28 февраля 2011

Почему при использовании события FormClosing код e.Cancel = true; работает, а new CancelEventArgs().Cancel = true; не работает?

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

    new CancelEventArgs().Cancel = true;
}

Ответы [ 4 ]

22 голосов
/ 28 февраля 2011

Событие вызвано сантехническим кодом Winforms. Единственный способ увидеть, что пользовательский обработчик событий хочет изменить поведение по умолчанию, - это объект e. Создание нового объекта CancelEventArgs не имеет побочных эффектов, которые может обнаружить сантехника.

Есть что-то еще не так, события генерируются для внешнего кода, давая ему знать, что происходит, и давая ему возможность изменить поведение. Здесь нет внешнего кода, обработчик события фактически является частью того же класса, который вызывает событие. Другими словами, форма слушает свои собственные события. Есть гораздо лучший способ справиться с этим, вы переопределяете метод, который вызывает событие. Как это:

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

Теперь внешний код может переопределить поведение по умолчанию, события возникают после , когда запускается метод OnXxxx. И у вас есть выбор: если вы не хотите, чтобы внешний код переопределял поведение, просто поменяйте местами два оператора.

15 голосов
/ 28 февраля 2011

Я думаю, что код делает именно то, что говорит; чего не хватает, так это буквального прочтения.

Когда вы присваиваете новое значение e.Cancel, вы изменяете e, который предоставляется в качестве параметра функции. После завершения функции обработчика события этот экземпляр FormClosingEventArgs, включая любые изменения, внесенные в него из обработчика события, будет доступен для любого кода, вызвавшего обработчик события. В данном случае это почти наверняка код Winforms, написанный Microsoft.

С другой стороны, когда вы внутри этого обработчика событий создаете новый экземпляр типа FormClosingEventArgs и что-то делаете с ним, ничто не может предоставить эту информацию вызывающей стороне; вам понадобится что-то явное для этого. Так как вызывающая сторона смотрит на значение параметра, который она передала после завершения обработчика события, вам нужно каким-то образом заменить содержимое e, как видно вызывающей стороне, на вновь созданный экземпляр. В других случаях такой результат может быть предоставлен как возвращаемое значение.

В общем случае результат new T() для некоторого типа T является экземпляром типа T. Таким образом, вы можете работать с результатом выражения new T(), как если бы вы имели ненулевую переменную типа T. В вашем конкретном случае вы присваиваете значение свойству типа T (в частности, создан экземпляр этого типа). (Существует особый случай, когда конструктор терпит неудачу, но давайте пока не будем здесь; для простых типов это в значительной степени будет означать, что вы находитесь в таком тяжелом положении, что ваша программа вряд ли сможет продолжить работу в любом случае. )

Здесь важно то, что, если вы нигде не назначите результат выражения new T() , вновь созданный экземпляр будет отброшен (технически становится недоступным) после завершения инструкции. Затем, в какой-то момент, включается сборщик мусора .NET и фактически освобождает выделенную память. На самом деле это ничем не отличается от размещения переменной в одной функции, вызова этой функции из другой функции и попытки доступа к переменной, выделенной таким образом из второй функции, без каких-либо действий для передачи переменной из первой функции во вторую, кроме как здесь. задействована только одна функция.

Выполнение чего-то вроде вашей второй строки кода в обработчике событий было бы довольно необычно, но может в принципе быть допустимым, если вызов конструктора имеет какой-то побочный эффект, который вы хотите использовать, например, запуск ленивой загрузки.

6 голосов
/ 21 февраля 2013

Этот код наверняка работает, просто проверьте его

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;
        }

Happy Coding

3 голосов
/ 03 мая 2013

Это потому, что CancelEventArgs - это ссылка на объект, передаваемая обработчику событий в вашем коде.Закулисный код вызывает FormClosing с объектом CancelEventArgs, и все обработчики событий получают этот же объект.После того как все обработчики имеют свою очередь, закулисный код проверяет отправленный им объект CancelEventArgs, чтобы увидеть, установлено ли его свойство Cancel на true.Если это так, он ничего не делает, и цепочка событий FormClose останавливается.Если Cancel равно false (CancelEventArgs значение по умолчанию), что означает, что он не был установлен в Cancel цепочку событий, то закулисный код продолжается, а затем вызывает событие FormClosed.

Вы можете прочитать больше на Событие Form.FormClosing на MSDN .

В Forms все события -ing обычно сопровождаются событием -ed.События -ing обычно имеют CancelEventArgs, у которого его свойство Cancel может быть установлено на true, чтобы остановить событие -ed.

...