.NET Reflector - ваш друг, когда узнаете, как работает WinForms.
Класс Form имеет внутреннее поле с именем closeReason , и оно используется при создании параметра события, который вы проверяете в событии Closing . Это внутреннее поле установлено в четырех разных местах, которые я могу найти. Это ...
1, Метод Form.Close () устанавливает значение closeReason = UserClosing.
Это имеет смысл, поскольку выполнение ручного вызова метода Form.Close () обычно является результатом некоторых действий пользователя, таких как опция меню File-> Exit , являющаяся выбранный пользователем. Очевидно, это действие пользователя.
2, WM_SYSCOMMAND (SC_CLOSE) устанавливает closeReason = UserClosing.
WndProc формы обрабатывает системную команду SC_CLOSE , устанавливая closeReason в UserClosing и позволяет стандартному окну proc выполнить и закрыть приложение. Это имеет смысл, поскольку эта SC_CLOSE отправляется, когда пользователь нажимает кнопку закрытия окна Chrome или выбирает параметр закрытия из щелчка правой кнопкой мыши на строке заголовка. Оба являются действиями пользователя, поэтому установка closeReason на UserClosing выглядит правильно.
3, WndProc обрабатывает сообщение WM_CLOSE
(0x10) с closeReadon = TaskManagerClosing
WM_CLOSE
отправляется диспетчером задач и другими приложениями для закрытия окна, и если closeReason в настоящее время равно Нет , он обновляет его до TaskManagerClosing, Обратите внимание, что эта проблема обновляется, только если она Нет , так как я думаю, что это проблема для вас.
4, WndProc обрабатывает сообщения 0x11 и 0x16 с closeReason = WindowsShutDown
Это не очень интересно, так как вы не заботитесь об этом сценарии, но это просто стандартная обработка завершенных сообщений.
Итак, основная проблема, с которой вы столкнулись, заключается в том, что closeReason ни при каких условиях не сбрасывается обратно на Нет при отмене события Closing . Поэтому пункт 3 выше никогда не будет корректно обновлять значение до TaskManagerClosing , если это произойдет после вашей отмены. Поскольку closeReasson является внутренним полем, вы не можете обновить его напрямую. Но вы можете обмануть, и это подход, который я использовал сам в прошлом. Вам нужно использовать отражение, чтобы получить доступ к внутреннему полю, а затем сбросить его на Нет , когда вы установите Cancel = true в обработчике событий.
Я не тестировал этот код, но вам нужно что-то вроде ...
PropertyInfo pi = typeof(Form).GetProperty("CloseReason",
BindingFlags.Instance |
BindingFlags.SetProperty |
BindingFlags.NonPublic);
pi.SetValue(this, CloseReason.None, null);