代码之家  ›  专栏  ›  技术社区  ›  Neo

当强制文本输入导致源值不变时,不更新updateSourceTrigger=propertyChanged的文本框上的文本

  •  13
  • Neo  · 技术社区  · 14 年前

    我有一个文本框 文本 属性A 两个星期 多重装订 具有 更新源触发器 设置为 属性更改 . 第一 结合 是到依赖属性( 价值 有A 属性更改回调 将值舍入到小数点后一位的函数。

    文本框的目的是作为用户类型执行舍入,而不是当文本框失去焦点时,因此为什么 更新源触发器 设置为 属性更改 .

    我的问题是,如果输入的文本不会导致 价值 改变, 文本 财产和 价值 变得不同步。仅当舍入操作导致 价值 改变世界 文本 即时更新。例如,如果 文本 价值 之后是123.4和用户类型1, 价值 四舍五入到相同的值(123.4),但 文本 显示123.41。但是,如果在4之后键入9, 价值 舍入到123.5。因为这个实际的变化, 文本 然后更新为相同(123.5)。

    是否有任何方法迫使文本框从源更新,即使源自上次触发器以来没有改变过吗?我试过用 BindingExpressionBase.UpdateTarget() 但这只在 更新源触发器 设置为 明确的 ,不能用作 价值 在合适的时间之前不再更新 更新数据集 可以调用(例如 文本输入框 处理程序)。我尝试过其他方法,例如显式更新 文本 来自绑定的值 价值 ,强制实际更改为 价值 临时调用更新,但这些“黑客”要么不起作用,要么导致其他问题。

    任何帮助都将不胜感激。

    代码如下。

    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>
    

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

    要求转换器类

    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
    }
    
    1 回复  |  直到 9 年前
        1
  •  10
  •   Community CDub    8 年前

    我在互联网上做了一些挖掘,结果发现这个在WPF 4中被破坏了。一个和我有着几乎相同问题的人发布在这里: http://www.go4answers.com/Example/textbox-shows-old-value-being-coerced-137799.aspx

    “答案8”指出这在WPF 4中被打破,并提出了一个实际使用的解决方案。 UpdateSourceTrigger="Explicit" 但要处理TextChanged事件并调用 bindingExpression.updateSource()。 强制文本框中的更改反映在基础值中,如同 UpdateSourceTrigger="PropertyChanged" ,根据本帖: Coerce a WPF TextBox not working anymore in .NET 4.0

    我实现了这一点,但是我发现还有其他的副作用,特别是每一次击键都会导致插入符号跳到文本框的开头,因为它更新了源代码并引发了 属性更改 事件。而且,为了输入更多的数字而输入的任何前导或尾随的零或小数位都会立即被清除。因此,检查文本框的已解析十进制值与基础值的简单条件解决了这个问题。

    只需要以下事件处理程序:

    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;
        }
    }
    
    推荐文章