Дополните созданный в cs-файле обработчик следующим образом:
После этого переместите текст Click="button1_Click" в открывающий тег родителя кнопки button1 (т. е. ближайшего к ней компонента StackPanel), дополнив имя Click префиксом Button:
Результат. Нажатие на любую кнопку приводит к отображению текста, указанного на этой кнопке, в метке label1 между полями ввода textBox1 и textBox2.
Комментарии
1. Поскольку при нажатии на любую из кнопок с обозначением арифметической операции следует выполнять однотипные действия, создавать для каждой кнопки особый обработчик события Click нецелесообразно. В приложениях Windows Forms в подобной ситуации создается один обработчик, который затем связывается с соответствующими событиями всех требуемых компонентов. Такой подход возможен и в WPF-приложениях. В нашем случае его можно реализовать, определив обработчик button1_Click для кнопки button1 и указав в xaml-файле атрибут Click="button1_Click" для всех четырех кнопок button1–button4. При этом оператор в обработчике button1_Click можно изменить, указав вместо e.Source параметр sender (оба варианта будут работать одинаково):
Однако в случае WPF-приложений можно использовать другой подход, который позволяет избежать явного связывания обработчика с событиями для нескольких компонентов. Подход основан на механизме маршрутизируемых событий (routed events), благодаря которому информация о возникших событиях может передаваться по цепочке компонентов. В WPF почти все стандартные события являются маршрутизируемыми. При этом все маршрутизируемые события делятся на три категории: прямые (direct events), которые ведут себя как обычные события .NET и не передаются по цепочке наследования (примером такого события является MouseEnter); туннелируемые (tunneling events), которые возникают в компоненте верхнего уровня и «спускаются» по цепочке его дочерних компонентов к компоненту, в котором фактически произошло действие, вызвавшее данное событие (например, событие PreviewTextInput, которое будет использовано далее в нашем проекте), и пузырьковые (bubbling events), которые «поднимаются» от компонента, где произошло событие, вверх по цепочке его родительских компонентов (например, событие MouseDown или использованное в данном пункте событие Click). Заметим, что в названиях всех туннелируемых событий используется префикс Preview и событие с таким префиксом наступает до наступления одноименного события без этого префикса.
На всем пути прохождения события оно может приводить к запуску связанных с ним обработчиков. Замечательной чертой механизма маршрутизируемых событий в WPF является то, что обработчик для маршрутизируемого события можно связать даже с тем родителем, для которого соответствующее событие не определено! Именно такая ситуации имеет место в нашем случае, поскольку для компонента StackPanel не предусмотрено событие Click. Тем не менее мы смогли связать с ним обработчик для события Click, которое может возникать в его дочерних компонентах (для этого нам потребовалось уточнить имя Click именем того компонента, для которого событие Click определено: Button.Click). Подобное поведение похоже на поведение присоединенных свойств (подробно рассмотренных в проекте EVENTS), поэтому в данной ситуации говорят о присоединенных событиях (attached events).
Теперь при возникновении события Click у любой из кнопок панели StackPanel оно «поднимется» к родителю-панели и приведет к вызову связанного с ним обработчика button1_Click. При этом в параметре sender обработчика будет указан компонент, в котором был вызван обработчик (в нашем случае панель StackPanel), а в свойстве Source второго параметра e будет указан компонент, в котором фактически произошло событие (в нашем случае одна из кнопок).