【问题标题】:Validating input which is databound to a DependencyProperty - Silverlight验证数据绑定到 DependencyProperty 的输入 - Silverlight
【发布时间】:2011-07-11 14:33:11
【问题描述】:

我的问题:我想使用控件的 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:使用依赖属性的验证导致“'System.Exception'类型的第一次机会异常......”并且应用程序停止工作。

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

我做错了什么?

【问题讨论】:

    标签: silverlight validation dependency-properties


    【解决方案1】:

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

    我怀疑您将 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 上显示验证工具提示。

    【讨论】:

      【解决方案2】:

      我对依赖属性不太熟悉,但我可以在你所说的第二个代码块中看到这一点

      if (TestText="!") {

      您需要将其替换为

      if( TestText == "!") {
      

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

      【讨论】:

      • 我怀疑出现 if (TestText="!") 行是因为 OP 已匿名化他/她的代码并在这样做时引入了该错误。上面显示的代码无法编译,因为 C# if 语句中的条件必须具有 bool 类型,但表达式 TestText="!" 具有 string 类型。
      • 啊,我以为它可能只是抛出一个警告。
      猜你喜欢
      • 2012-07-24
      • 1970-01-01
      • 2012-01-31
      • 2014-12-22
      • 1970-01-01
      • 2011-03-18
      • 1970-01-01
      • 2012-04-04
      • 2021-04-27
      相关资源
      最近更新 更多