Если вы запустите свой второй пример и посмотрите на стек вызовов при возникновении исключения, вы увидите, что он вообще не проходит через систему зависимостей.Текст текстового поля изменился, обработчик событий запущен, и возникла исключительная ситуация.Вот почему приложение умирает.
Я подозреваю, что вы включили этот обработчик события TextChanged, потому что ваш OnTestTextChanged
метод не вызывался.Как это происходит, есть причина для этого, но это немного неуловимо, и я не могу найти документацию, чтобы поддержать это.Я называю это поведение «черным списком».Короче говоря, если у вас есть PropertyChangedCallback для свойства зависимостей, а PropertyChangedCallback вызывает то же свойство зависимости, которое устанавливается, прямо или косвенно, PropertyChangedCallback получает «черный список» и никогда не вызывается снова.
Your PropertyChangedCallbackвыглядит следующим образом:
static void OnTestTextChanged(object sender, DependencyPropertyChangedEventArgs args) {
MyControl source = (MyControl)sender;
source.TestTextBox.Text = (String)args.NewValue; // *******
}
Проблема с звездочкой здесь.Происходит следующее:
- Вы устанавливаете свойство
Text
TextBox, - Silverlight, затем обновляет значение вашего свойства зависимости
TestText
, используя привязку, - это приведет к другому вызову в ваш PropertyChangedCallback.
Однако в этот момент Silverlight понимает, что он делает рекурсивный вызов к вашему PropertyChangedCallback, и вместо повторного вызова решает:черный списокВ результате этого «черного списка» ваш PropertyChangedCallback больше никогда не вызывается.Досадно, что при этом нет ошибок или предупреждений.
Я не уверен, почему он не выдает никаких предупреждений или ошибок.Однако, если он не «занесет в черный список» ваш PropertyChangedCallback и продолжит вызывать его, вы получите переполнение стека.
Итак, как вы исправите свой код?Ну, для начала я хотел бы ввести золотое правило работы со свойствами зависимостей Silverlight (и WPF), которое нарушает ваш код:
УСТАНОВКА В ИМУЩЕСТВЕ, ОСНОВАННАЯ СОБСТВЕННОСТЬЮ ЗАВИСИМОСТИСЛЕДУЕТ ВЫЗВАТЬ SetValue
И НЕ ДЕЛАТЬ БОЛЬШЕ. Все, что вы хотите сделать, когда значение изменения свойства зависимости должно идти в PropertyChangedCallback и NOT в установщике свойства.
Если вы не придерживаетесь этого правила, вы попадаете в мир боли.
Поэтому ваше свойство TestText
должно выглядеть следующим образом:
public String TestText
{
get { return (String)GetValue(TestTextProperty); }
set { SetValue(TestTextProperty, value); }
}
и вместо этого вы должны выполнить проверку в свой PropertyChangedCallback:
static void OnTestTextChanged(object sender, DependencyPropertyChangedEventArgs args)
{
if ((string)args.NewValue == "!")
{
throw new Exception("No ! allowed!");
}
}
После внесения этих изменений в ваш код я смог запустить его и получить подсказку для проверки, которая будет отображаться в TextBox при вводе текста!
.