验证数据绑定到DependencyProperty的输入-Silverlight [英] Validating input which is databound to a DependencyProperty - Silverlight

查看:103
本文介绍了验证数据绑定到DependencyProperty的输入-Silverlight的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My problem: I would like to validate the user input of a TextBox using the control's ValidatesOnExceptions property.

XAML代码:

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



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



ViewModel代码:

1 : The validation using a normal property works fine:

ViewModel code:

private string _testText, 

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



2:使用依赖项属性进行的验证会导致类型为'System.Exception'...的第一次机会异常,应用程序将停止运行。



ViewModel代码:

2: The validation using a Dependency Property causes "A first chance exception of type 'System.Exception'..." and the application stops working.

ViewModel code:

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;
    }
}

我在做什么错了?

推荐答案

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

If you run your second example and take a look at the call stack when the exception gets thrown, you'll see that it's not going through the dependency system at all. The textbox's text changed, the event handler runs and that encountered an exception. That's why the application dies.


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

I suspect you put that TextChanged event handler in because your OnTestTextChanged method wasn't being called. As it happens, there's a reason for this, but it's a bit subtle and I can't find any documentation to back it up. I refer to this behaviour as 'blacklisting'. In short, if you have a PropertyChangedCallback on a dependency property, and the PropertyChangedCallback causes the same dependency property to be set, either directly or indirectly, the PropertyChangedCallback gets 'blacklisted' and never gets called again.

您的PropertyChangedCallback如下:

Your PropertyChangedCallback is as follows:

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

星号是这里的问题。发生的情况如下:

The asterisked line is the problem here. What happens is as follows:


  • 您设置了TextBox的 Text 属性,

  • Silverlight然后使用绑定更新 TestText 依赖项属性的值,

  • this

  • you set the Text property of the TextBox,
  • Silverlight then updates the value of your TestText dependency property using the binding,
  • this would cause another call into your PropertyChangedCallback.

但是,在这一点上,Silverlight意识到它正在对PropertyChangedCallback进行递归调用,并且无需再次调用它,而是决定将其黑名单。由于此列入黑名单,您的PropertyChangedCallback不再被调用。令人讨厌的是,这样做时没有错误或警告。

However, at this point Silverlight realises that it is making a recursive call to your PropertyChangedCallback, and instead of calling it again, decides to 'blacklist' it. As a result of this 'blacklisting', your PropertyChangedCallback never gets called again. Annoyingly, there's no error or warning when it does this.

我不确定为什么它没有给出任何警告或错误。但是,如果它没有将您的PropertyChangedCallback列入黑名单并继续对其进行调用,则会导致堆栈溢出。

I'm not sure why it doesn't give any warnings or errors. However, if it didn't 'blacklist' your PropertyChangedCallback and continued to call it, you'd end up with a stack overflow.

那么,如何修复代码?好吧,首先,我想介绍一个使用Silverlight(和WPF)依赖项属性的黄金法则,您的代码违反了该规则:

So, how do you fix your code? Well, to start with, I'd like to introduce a golden rule of working with Silverlight (and WPF) dependency properties, which your code violates:

THE设置属性依赖的属性中的设置器,应该 SetValue ,并且不要做任何其他事情。只要...的值依赖项属性更改必须放在属性设置器的PropertyChangedCallback中,并且

THE SETTER IN THE PROPERTY BACKED BY THE DEPENDENCY PROPERTY SHOULD CALL SetValue AND DO NOTHING MORE. Anything you want to do whenever the value of the dependency property changes must go in a PropertyChangedCallback and NOT in the property setter.

如果您不遵守此规则,进入痛苦的世界。

If you don't stick to this rule, you are entering a world of pain.

您的 TestText 属性应如下所示:

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

相反,您应该在PropertyChangedCallback中进行验证:

and instead you should do the validation in your PropertyChangedCallback:

    static void OnTestTextChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        if ((string)args.NewValue == "!")
        {
            throw new Exception("No ! allowed!");
        }
    }

对您的代码进行这些更改之后,我能够运行它并获得验证工具提示,当我输入文本

After making these changes to your code, I was able to run it and get a validation tooltip to show on the TextBox when I entered the text !.

这篇关于验证数据绑定到DependencyProperty的输入-Silverlight的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆