1.5. Присоединение к событию другого обработчика
Для того чтобы прирученная кнопка при нажатии на нее выполняла какие-либо действия, можно добавить эти действия к уже имеющемуся обработчику button2_Click. Однако в этом случае обработчик должен проверять, в каком состоянии находится кнопка – диком или прирученном. Поступим по-другому: свяжем событие Click для прирученной кнопки с новым обработчиком. Такой подход позволит продемонстрировать в нашем проекте ряд особенностей, связанных с действиями по присоединению и отсоединению обработчиков.
Новый обработчик (назовем его button2_Click2) создадим «вручную», не прибегая к услугам окна Properties или xaml-файла. Для этого в конце описания класса MainWindow в файле MainWindow.xaml.cs (перед двумя последними скобками «}») добавим описание этого обработчика:

Чтобы подчеркнуть, что в данном случае никакая часть обработчика не создается автоматически, мы выделили весь текст обработчика полужирным шрифтом.
В метод button2_Click добавьте следующие операторы (здесь и далее в книге предполагается, что если место добавления не уточняется, то операторы надо добавлять в конец метода):

В метод Canvas_MouseDown добавьте операторы:
Результат. Прирученная кнопка теперь выполняет полезную работу – щелчок на ней приводит к разворачиванию окна программы на весь экран, а новый щелчок восстанавливает первоначальное состояние окна. Если же щелкнуть мышью на окне (не на кнопке), то услужливая кнопка «Закрыть» прибежит на вызов, а прирученная кнопка «Изменить» снова одичает, потеряет текст своего заголовка и начнет убегать от мыши.
Комментарий
Приведенные тексты методов показывают, что при смене обработчика недостаточно присоединить к событию новый обработчик; необходимо также отсоединить от события обработчик, ранее связанный с ним. Данное обстоятельство обусловлено тем важным фактом, что к одному и тому же событию можно последовательно присоединить несколько обработчиков (для этого достаточно применить к этому событию несколько раз оператор +=). Следует отметить, что данная возможность для событий визуальных компонентов применяется крайне редко (достаточно отметить, что с помощью окна Properties или xaml-файла присоединить к одному событию несколько обработчиков нельзя). В то же время при явном присоединении обработчиков эта особенность может приводить к появлению трудно выявляемых ошибок, если, например, один и тот же обработчик будет присоединен к событию несколько раз. Подобные проблемы можно проиллюстрировать с помощью нашей программы, если закомментировать заголовок оператора if в обработчике Canvas_MouseDown:

Если теперь после запуска программы несколько раз щелкнуть мышью на окне, а затем приручить кнопку button2, то при ее последующем нажатии окно несколько раз последовательно перейдет из развернутого состояния в стандартное и обратно. Это объясняется тем, что теперь каждый щелчок на окне присоединяет к событию Click кнопки button2 новый экземпляр обработчика button2_Click, и при нажатии на эту кнопку каждый экземпляр обработчика последовательно запускается на выполнение. Ситуация осложняется еще тем обстоятельством, что в программе невозможно выяснить, сколько и какие обработчики присоединены в настоящий момент к данному событию (а не зная этого, нельзя и обеспечить отсоединение от события всех его обработчиков).
Итак, к действиям по явному присоединению обработчика к событию и его последующему отсоединению следует подходить крайне осторожно.
Недочет. При выполнении программы может возникнуть ситуация, когда одна или обе кнопки не будут отображаться в окне (если, например, кнопки были перемещены на новое место при развернутом окне, после чего окно возвращено в исходное состояние).
Исправление. Определите для окна обработчик события SizeChanged:

Результат. Теперь в ситуации, когда при изменении размера окна его кнопки оказываются вне клиентской части, происходит перемещение этих кнопок на исходные позиции около левого верхнего угла окна.
Комментарии
1. В данном обработчике демонстрируется еще один способ доступа к компонентам окна, который удобен для организации перебора в цикле компонентов с похожими именами. Этот способ основан на применении метода FindName, который можно вызывать непосредственно для окна. Метод FindName возвращает компонент окна с указанным именем (или null, если компонент с таким именем в окне отсутствует).
2. Вместо статического метода GetLeft для получения значения присоединенного свойства Left можно было бы использовать более длинный, но и более универсальный вариант, использующий метод GetValue того компонента, к которому ранее было присоединено свойство: (double)b.GetValue(Canvas.LeftProperty). Аналогичным образом можно получить значение свойства Top (и любых других свойств зависимости, присоединенных к данному компоненту).
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.