验证数据绑定到DependencyProperty的输入 - Silverlight

时间:2011-07-11 14:33:12

标签: silverlight validation dependency-properties

我的问题:我想使用控件的ValidatesOnExceptions属性来验证TextBox的用户输入。

XAML代码:

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

1:使用普通属性进行验证工作正常:

ViewModel代码:

private string _testText, 

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

2:使用依赖属性进行验证会导致&#34;类型&#39; System.Exception&#39; ...&#34;的第一次机会异常。并且应用程序停止工作。

ViewModel代码:

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 个答案:

答案 0 :(得分:4)

如果运行第二个示例并在抛出异常时查看调用堆栈,您将看到它根本没有通过依赖系统。文本框的文本已更改,事件处理程序运行并遇到异常。这就是应用程序死亡的原因。

<击> 我怀疑您将TextChanged事件处理程序放入,因为未调用OnTestTextChanged方法。碰巧,这是有原因的,但它有点微妙,我找不到任何备份文件。我将此行为称为“黑名单”。简而言之,如果在依赖项属性上有PropertyChangedCallback,并且PropertyChangedCallback导致直接或间接设置相同的依赖项属性,则PropertyChangedCallback将被“列入黑名单”并且永远不会再被调用。

<击>

您的PropertyChangedCallback如下:

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

星号线是这里的问题。会发生什么如下:

  • 您设置了TextBox的Text属性,
  • 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上显示。

答案 1 :(得分:0)

我对依赖属性并不熟悉,但我可以在你说的第二段代码中看到

if(TestText =“!”){

您需要用

替换它
if( TestText == "!") {

您的代码将TestText设置为值“!”而不是检查它们是否是相同的字符串。