我的问题:我想使用控件的ValidatesOnExceptions属性来验证TextBox的用户输入。
XAML代码:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
...
<TextBox x:Name="TestTextBox" Text="{Binding TestText, Mode=TwoWay, ValidatesOnExceptions=True}" TextChanged="TestTextBox_TextChanged"/>
ViewModel代码:
private string _testText,
public string TestText {
get {return _testText;}
set {
if (value=="!")
throw new Exception("Error: No ! allowed!");
_testText = value;
}
}
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;
}
}
我做错了什么?
答案 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; // *******
}
星号线是这里的问题。会发生什么如下:
Text
属性,TestText
依赖项属性的值
但是,此时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设置为值“!”而不是检查它们是否是相同的字符串。