带有UpdateSourceTrigger的TextBox上的文本=当文本输入的强制导致源值保持不变时,不会更新PropertyChanged

Neo*_*Neo 13 binding textbox updatesourcetrigger propertychanged multibinding

我有一个文本框,其Text属性具有TwoWay MultiBinding,UpdateSourceTrigger设置为PropertyChanged.第一个Binding是一个依赖属性(Value),它有一个PropertyChangedCallBack函数,可以将值四舍五入到一个小数位.

文本框的目的是在用户键入时执行舍入,而不是在文本框失去焦点时执行舍入,因此将UpdateSourceTrigger设置为PropertyChanged.

我遇到的问题是,如果输入的文本不会导致更改,则Text属性和Value将变得不同步.仅当舍入操作导致更改时,文本才会动态更新.例如,如果TextValue都是123.4并且用户在此之后键入1,则Value将四舍五入为相同的值(123.4),但Text显示为123.41.但是,如果在4之后键入9,则向上舍入为123.5.由于这个实际的变化,文本然后更新为相同(123.5).

是否有任何方法强制文本框从其源更新,即使源自上次触发后没有更改?我尝试过使用BindingExpressionBase.UpdateTarget()但这仅在UpdateSourceTrigger设置为Explicit时有效,不能用作在可以调用UpdateTarget的合适时间之前不再更新的(例如TextInput处理程序).我已经尝试过其他方法,例如从绑定显式更新Text值,暂时强制实际更改为Value以调用更新,但这些"hacks"要么不起作用,要么导致其他问题.

任何帮助将不胜感激.

代码如下.

XAML片段

<TextBox>
  <TextBox.Text>
    <MultiBinding Converter="{local:NumberFormatConverter}"
                  UpdateSourceTrigger="Explicit"
                  Mode="TwoWay">
      <Binding Path="Value"
               RelativeSource="{RelativeSource AncestorType={x:Type Window}}"
               Mode="TwoWay" />
    </MultiBinding>
  </TextBox.Text>
</TextBox>
Run Code Online (Sandbox Code Playgroud)

C#片段

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register(
        "Value", typeof(decimal), typeof(MainWindow),
        new FrameworkPropertyMetadata(0m,
        new PropertyChangedCallback(OnValueChanged)));

private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    obj.SetValue(ValueProperty, Math.Round((decimal)args.NewValue, 1));
}
Run Code Online (Sandbox Code Playgroud)

需要转换器类

public class NumberFormatConverter : MarkupExtension, IMultiValueConverter
{
    public static NumberFormatConverter Instance { private set; get; }

    static NumberFormatConverter()
    {
        Instance = new NumberFormatConverter();
    }

    public override object ProvideValue(IServiceProvider serviceProvider_)
    {
        return Instance;
    }

    #region Implementation of IMultiValueConverter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values[0].ToString();
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        var result = 0m;
        if (value != null)
        {
            decimal.TryParse(value.ToString(), out result);
        }
        return new object[] { result };
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

Neo*_*Neo 10

我在互联网上做了一点挖掘,结果发现这在WPF 4中被破坏了.有人问我几乎完全相同的问题:http: //www.go4answers.com/Example/textbox-shows-old-值感-裹挟-137799.aspx

'答案8'声明这在WPF 4中被破坏并提出了一个解决方案,它实际上是UpdateSourceTrigger="Explicit"用来处理TextChanged事件并调用BindingExpression.UpdateSource()来强制文本框中的更改反映在基础值中,就像UpdateSourceTrigger="PropertyChanged",根据这篇文章: 强制WPF TextBox在.NET 4.0中不再工作

我实现了这个,但是看到还有更多的副作用,特别是每次击键都会导致插入符号由于更新源和引发PropertyChanged事件而跳转到文本框的开头.此外,为了输入更多数字而输入的任何前导或尾随零或小数位将立即被删除.因此,检查文本框的解析十进制值与基础值的简单条件解决了这个问题.

只需以下事件处理程序:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    var tb = (TextBox)e.Source;
    MultiBindingExpression binding = BindingOperations.GetMultiBindingExpression(tb, TextBox.TextProperty);

    decimal result = 0m;
    decimal.TryParse(tb.Text, out result);

    if ((decimal)GetValue(ValueProperty) != result && binding != null)
    {
        int caretIndex = tb.CaretIndex;
        binding.UpdateSource();
        tb.CaretIndex = caretIndex;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这解决了我的问题。给未来的读者一个简短的说明:我必须将“MultiBindingExpression”用法更改为“BindingExpression”,因为我在 TextBox 上使用常规绑定。 (2认同)