Проверка ввода, который связан с данными DependencyProperty - Silverlight - PullRequest
0 голосов
/ 11 июля 2011

Моя проблема: я хотел бы проверить пользовательский ввод TextBox, используя свойство ValidatesOnExceptions элемента управления.

XAML код:

DataContext="{Binding RelativeSource={RelativeSource Self}}"       
...
<TextBox x:Name="TestTextBox" Text="{Binding TestText, Mode=TwoWay, ValidatesOnExceptions=True}" TextChanged="TestTextBox_TextChanged"/>

1: проверка с использованием обычного свойства работает нормально:

Код модели представления:

private string _testText, 

public string TestText {
    get {return _testText;} 
    set { 
        if (value=="!")
            throw new Exception("Error: No ! allowed!");
        _testText = value;
    }
}

2: проверка с использованием свойства зависимости вызывает «Первое исключение типа« System.Exception »...», и приложение перестает работать.

Код модели представления:

public partial class MyControl : UserControl {
    public MyControl() {
        InitializeComponent();
    }

    public static readonly DependencyProperty TestTextProperty = DependencyProperty.Register("TestText", typeof(String), typeof(MyControl), new PropertyMetadata("DefaultText", new PropertyChangedCallback(OnTestTextChanged)));

    public event TextChangedEventHandler TestTextChanged;

    public String TestText {
        get {
            return (String)GetValue(TestTextProperty);
        }
        set {
            SetValue(TestTextProperty, value);

            if (TestTextChanged != null) {
                TestTextChanged(TestTextBox, null);
            }

            if (TestText=="!") {
                throw new Exception("No ! allowed!");
            }
        }
    }

    static void OnTestTextChanged(object sender, DependencyPropertyChangedEventArgs args) {
        MyControl source = (MyControl)sender;
        source.TestTextBox.Text = (String)args.NewValue;
    }

    private void TestTextBox_TextChanged(object sender, TextChangedEventArgs e) {
        TextBox source = (TextBox)sender;
        TestText = source.Text;
    }
}

Что я делаю не так?

Ответы [ 2 ]

4 голосов
/ 22 июля 2011

Если вы запустите свой второй пример и посмотрите на стек вызовов при возникновении исключения, вы увидите, что он вообще не проходит через систему зависимостей.Текст текстового поля изменился, обработчик событий запущен, и возникла исключительная ситуация.Вот почему приложение умирает.

Я подозреваю, что вы включили этот обработчик события 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 при вводе текста!.

0 голосов
/ 21 июля 2011

Я не очень знаком со свойствами зависимостей, но я вижу это в вашем втором блоке кода, где вы говорите

if (TestText = "!") {

вам нужно заменить это на

if( TestText == "!") {

ваш код устанавливал TestText в значение "!" вместо проверки, являются ли они одной и той же строкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...