Обработка системной кнопки

Пока в приложение закрался один существенный недостаток. Когда документ содержит несохраненные изменения и пользователь завершает работу приложения по нашей команде Exit, то все в порядке - приложение извещает о необходимости их сохранить. Но когда окно закрывается по системной кнопке, то извещение отсутствует. Исправим это, для чего воспользуемся событием Closing. В отличии от Closing событие Closed возбудается, когда отменить закрытие окна уже невозможно, а можно только что-то доделать.

  • Присоедините к открывающему дескриптору окна Window1 в файле Window1.xaml обработчик события Closing, которое будет возбуждаться при попытке закрытия окна любым способом
<Window x:Class="Notepad1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1: Управление состоянием источников команд" Width="500" Height="375" MinWidth="500" MinHeight="375" WindowStartupLocation="CenterScreen" ResizeMode="CanResizeWithGrip" Loaded="Window_Loaded" Icon="Notepad.ico" Closing="Window_Closing" >
  • Заполните обработчик события Closing следующим кодом
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (!CheckModifiedAndSaveIt()) { e.Cancel = true; return; // Пользователь передумал выходить } }
  • Запустите приложение - теперь сообщение о несохраненных изменениях выводится и при попытке закрытия окна системной кнопкой

Обратите внимание, что при закрытии окна через наше меню задачей Exit на кнопку отказа от сохранения надо щелкать 2 раза. Это связано с тем, что в обработчике события Closing проверка повторяется. Значит при выходе через меню проверку в обработчике события Closing нужно блокировать с помощью флага.

  • Добавьте в класс Window1 поле-флаг _IsExitItem и модифицируйте соответствующим образом обработчики
bool _IsExitItem = false; private void ExitOnExecute(object sender, RoutedEventArgs e) { if (!CheckModifiedAndSaveIt()) return; // Пользователь передумал выходить _IsExitItem = true; Close(); }private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { /* // Эта проверка была бы надежнее if(_IsExitItem) return; */ // !_IsExitItem должен в условии стоять первым if (!_IsExitItem && !CheckModifiedAndSaveIt()) { e.Cancel = true; _IsExitItem = false; return; // Пользователь передумал выходить } }

В последнем обработчике есть один поучительный нюанс: если в условии проверку значения флага поставить последним, то код будет реагировать на наши нововведения. Это происходит потому, что логическое умножение проверяется компилятором слева направо до первого ложного значения. В нашем случае если флаг _IsExitItem==true, то функция CheckModifiedAndSaveIt() выполняться уже не будет. Такой код менее надежен, поскольку зависит от компилятора, да и мы (или сопровождающий программист) можем случайно переставить члены выражения местами. Поэтому лучше заменить этот код на более ясный, как показано в коментариях.

  • Запустите приложение и испытайте работу закрытия окна при несохраняемых изменениях