为什么绑定设置在.NET 4与.NET 3.5中的行为不同

我有一个应用程序,我最近从VS 2008 .NET 3.5项目转换为VS2010 .NET 4项目。 转换后,项目中的某些WPF对话框的行为有所不同。 我想了解是什么导致了这种行为上的差异,所以我可以找到并修复现在可能存在问题的其他方面。

作为一个例子,我有一个MVVM对话框,让用户输入一个数字。 该数字在内部存储为double,如果用户输入的文本是有效的double,则用户只能接受该对话框。 所以我有一个文本框绑定到ViewModel中的字符串,并且一个OK按钮仅在字符串是有效的double时启用。 相关的Xaml看起来像这样:

  

ViewModel看起来像:

 class ViewModel : INotifyPropertyChanged { private double actualValue; public string ValueString { get { return actualValue.ToString("G3"); } set { double doubleValue; if (double.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out doubleValue)) { actualValue = doubleValue; ValueIsValid = true; RaisePropertyChanged("ValueString"); } else { ValueIsValid = false; } } } private bool valueIsValid = true; public bool ValueIsValid { get { return valueIsValid; } set { if (valueIsValid != value) { valueIsValid = value; RaisePropertyChanged("ValueIsValid"); } } } private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } public event PropertyChangedEventHandler PropertyChanged; } 

这在.NET 3.5中运行良好,但是当它在.NET 4上运行时,在用户输入数字时会出现问题。 例如,如果用户在.NET 3.5版本的文本框中输入“3.05555”,一切都很好。 但是在.NET 4版本中,它们可以输入3.05,但是当它们键入下一个“5”时,文本框的值将更改为“3.06”,如果再次按5则会更改为“3.07”。 就好像该值一旦被设置(即格式化为“G3”)就从ValueString属性读回,但这不适用于.NET 3.5。

我已经了解了.NET Framework 4中 的新function (包括WPF第4版中的新function ),但我没有发现任何有关此更改的信息。

如果你想亲自看看这个,我已经创建了一个小例子VS2010解决方案,你可以从这里下载 。 BindingTest2008项目已从VS 2008转换为目标.NET 3.5,而BindingTest2010项目是在VS 2010中针对.NET 4创建的。两个项目中的代码相同,但.NET 4项目存在此问题。

在理解为什么会发生这种情况时,我会感激不尽。 谢谢。

更新 :删除调用RaisePropertyChanged("ValueIsValid"); 不改变行为并键入无效数字(例如“3.1a”)不会被中间的最后一个有效数字替换(例如在这种情况下为“3.1”)。 也可以输入数字,其精度高于3位有效数字。 例如“3.0545555” – 当你输入的东西会导致第三个重要数字的四舍五入时,似乎只会发生这个问题。

这种行为差异的原因是:

在3.5中,绑定会在每次击键后将新值写回源,而不更改TextBox文本。 但是该文本可能并不准确地代表源的值,可能是因为它不包括格式和转换,或者因为源将值(在属性设置器中)更改为其他值。 这导致了频繁和激烈的抱怨 – 人们希望TextBox显示源的值,就像TextBlock绑定到具有相同转换器和格式的相同属性一样。 UI应显示数据中实际存在的内容,而不是最终用户键入的内容。

要在4.0中修复此类错误,绑定现在会在每次更新后将格式化和转换应用于源的新值。 (LostFocus绑定已在3.5中完成此操作。)TextBox现在显示数据中的内容,但这可能会使用户的输入更复杂。

我们计划在下一个版本中以至少两种方式改进这种情况:1。当TextBox文本被修改后的字符串替换时,用于旧字符串的插入点(游标)可能不再适用于新字符串。 可以改进猜测放置光标位置的启发式方法。 2.绑定将揭示在每次击键后使用部分validation进行LostFocus(或显式)更新的方法。 格式化/转换仅在焦点更改时应用,但用户在每次击键后都会获得validation反馈。

  • 山姆(WPF队)

从“ 将.Net 3.5更改为.Net 4.0文本框格式的.Net 4.0,当PropertyChanged用作UpdateSourceTrigger时 ”

看起来问题在于这一行:

  get { return actualValue.ToString("G3"); } 

.Net 4版本的行为正确,因为该值使用“G3”格式字符串格式化,这意味着结果字符串中将有3位有效数字(3.055变为3.06)。

3.5和4之间的区别在于,显然,绑定系统略有变化。 在3.5中,当调用属性的setter并且它引发PropertyChanged事件时,不会重新评估绑定(不调用getter)。 在.Net 4中,在触发PropertyChanged事件之后,重新评估绑定,即调用属性IS的getter,并在文本框中显示getter返回的值。