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

时间:2011-01-17 12:02:06

标签: c# wpf xaml c#-4.0

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

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

<TextBox Text="{Binding ValueString, UpdateSourceTrigger=PropertyChanged}"/>
<Button IsEnabled="{Binding ValueIsValid}">OK</Button>

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。

我查看了What's New in the .NET Framework 4(包括What's New in WPF Version 4),但我没有发现任何有关此更改的信息。

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

我很感激任何帮助,了解为什么会发生这种情况。 感谢。

已更新:删除呼叫RaisePropertyChanged("ValueIsValid");不会更改行为并输入无效号码(例如“3.1a”)并不会被中一个有效号码替换(例如“3.1”)。也可以输入数字,其精度高于3位有效数字。例如。 “3.0545555” - 这个问题似乎只发生在你输入​​的东西会导致第三个重要数字的四舍五入。

2 个答案:

答案 0 :(得分:5)

这种行为差异的原因是:

  

在3.5中,绑定会写一个新的   每次都回到源头   按键,不改变   TextBox文本。但该文本可能不会   代表来源的价值   准确地说,也许是因为它没有   包括格式和转换,或   因为来源改变了价值   (在物业设定者中)的东西   其他。这导致频繁和   激烈的抱怨 - 人们想要的   TextBox显示源代码   值,就像TextBlock那样   绑定到相同的属性与   相同的转换器和格式。用户界面   应该显示实际中的内容   数据,而不是最终用户键入的内容。

     

要修复4.0中的这类错误,   绑定现在应用格式和   转换为源的新值   每次更新后。 (引发LostFocus   绑定已经在3.5中做到了这一点。)   TextBox现在显示数据中的内容,   但这可以使用户打字   更复杂。

     

我们计划改善这种情况   下一个版本至少有两种方式:   1.当TextBox文本替换为修改后的字符串时,插入   点(光标)适用于旧的   字符串可能不再正确   新的字符串。启发式的   猜猜光标可以放在哪里   改进。   2.绑定将揭示一种使用LostFocus(或Explicit)更新的方法   每次之后部分验证   按键。格式/转换   仅在焦点更改时应用,   但是用户得到了验证反馈   每次按键后。

     
      
  • Sam(WPF团队)
  •   

来自“Changed behaviour from .Net 3.5 to .Net 4.0 of WPF TextBox formatting when PropertyChanged is used as UpdateSourceTrigger

答案 1 :(得分:2)

看起来问题就在这一行:

 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返回的值。