Результат. При изменении операции или содержимого текстовых полей результат предыдущего вычисления стирается. Это важная возможность, позволяющая предотвратить рассогласование отображаемых данных. При ее отсутствии возможна ситуация, когда после выполнения, например, вычислений вида 3 + 2 (с результатом 5), пользователь изменит первый операнд на 2, получив на экране текст 2 + 2 = 5.
Комментарии
1. Здесь мы использовали более традиционный способ связывания одного обработчика события с несколькими компонентами – путем указания этого обработчика в xaml-файле в описании каждого компонента.
Впрочем, в данном случае тоже можно было воспользоваться механизмом маршрутизируемых событий и после создания обработчика textBox1_TextChanged для компонента textBox1 не копировать соответствующий атрибут в компонент textBox2, а переместить его в родительский компонент StackPanel, снабдив префиксом TextBox:
2. Указание обработчиков событий, подобных событию TextChanged, непосредственно в xaml-файле может приводить к неожиданным ошибкам. Например, если закомментировать условный оператор в методе textBox1_TextChanged
то при запуске программы возникнет исключение NullReferenceException («Ссылка на объект не указывает на экземпляр объекта»). Это связано с тем, что в WPF событие TextChanged возникает сразу после конструирования поля ввода (при присваивания свойству Text начального значения). Но в момент создания поля ввода textBox1 метка label2 еще не существует, поскольку компоненты создаются в порядке их указания в xaml-файле, что и приводит к возникновению исключения.
Мы избежали этой ошибки, добавив проверку в обработчик. Исправить подобную ошибку можно и другим способом: не добавляя проверку в метод textBox1_TextChanged, удалить оба атрибута TextChanged="textBox1_TextChanged" в xaml-файле и вместо этого добавить в конец конструктора MainWindow операторы
Благодаря этим операторам связывание события TextChanged с обработчиками будет происходить уже после создания всех компонентов окна, и попытки обращения к неинициализированной метке не произойдет.
При анализе данного исправления возникает естественный вопрос: можно ли в программном коде связать требуемый обработчик с общим родителем обоих полей ввода – панелью StackPanel (подобно тому, как это делается в xaml-файле – см. комментарий 1)? Этому препятствуют два обстоятельства: во-первых, данная панель не имеет имени, с помощью которого к ней можно было бы обратиться в коде, и, во-вторых, в компоненте StackPanel отсутствует событие TextChanged. Первую проблему легко решить, добавив к описанию панели в xaml-файле атрибут x:Name. Вторая проблема решается благодаря наличию у любого компонента метода AddHandler, позволяющего связать с компонентом обработчик события даже в случае, если это событие для компонента не предусмотрено. Между прочим, первую из отмеченных проблем можно вообще не решать, если связать обработчик с родителем более высокого уровня – окном MainWindow. Таким образом, вместо указанных выше двух операторов достаточно добавить в конструктор окна следующий вызов метода AddHandler:
Обратите