WPF:文本框和绑定到 Double 无法键入。在它上面

问题描述 投票:0回答:8
wpf mvvm
8个回答
17
投票

每次值发生变化时,您都会更新您的属性。当您输入

.
时,它会被写入您的视图模型中并更新视图。

例如如果您输入

100.
,它会四舍五入为
100
,因此您永远不会看到任何点。

您有一些选项可以改变此行为:

使用延迟绑定:

<TextBox Text="{Binding Path=TransactionDetails.TransactionAmount, 
                        Mode=TwoWay, 
                        UpdateSourceTrigger=PropertyChanged, 
                        Delay=250}" 
         Grid.Column="3" 
         Grid.ColumnSpan="2" 
         Grid.Row="5" 
         x:Name="TextBoxAmount" />

仅在与保存的值不同时更改该值 (我建议每个绑定都使用这个):

private double _transactionAmount; 
public double TransactionAmount  
{
  get { return _transactionAmount; }    
  set
  { 
    if (_transactionAmount != value)
    {
      _transactionAmount = value; 
      Notify("TransactionAmount"); 
    }
  }

或使用某种验证,例如验证异常。


6
投票

当您的应用程序面向 .NET 4.0 或更早版本时,该行为符合预期,但后来发生了更改 (MSDN)。可以通过设置恢复旧的行为:

System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;

尽早设置(例如在 App.cs 的构造函数中),否则框架会引发异常。

来源及详细解释:https://web.archive.org/web/20220127083119/https://www.mobilemotion.eu/?p=1855


5
投票

我通过使用

StringFormat

得到的最佳解决方案
<TextBox Text="{Binding TransactionDetails.TransactionAmount, Mode=TwoWay, 
UpdateSourceTrigger=PropertyChanged,StringFormat=N2}" Grid.Column="3" 
Grid.ColumnSpan="2" Grid.Row="5" x:Name="TextBoxAmount" />

我们也可以根据要求定制字符串格式


1
投票

您的问题出在 UpdateSourceTrigger 上。 你可以使用这样的东西,而不是在那里使用,

private double amount;
public double Amount
    {
        get
        {
            return amount;
        }
        set
        {
            amount= value;
            PropertyChanged();
            Calculation();
        }
    }

PropertyChanged() 您将从 INotifyPropertyChanged 中获取它。欲了解更多信息,请点击此处 https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx


1
投票

绑定双精度类型源数据时,可以用此类替换默认转换器。这样使用起来比较方便。下面是代码:

public class double2txtConverter : IValueConverter
    {
        string _strCache;
        double _dCache;
        //Convert double to string of textbox.
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (_dCache == (double)value)
                return _strCache;
            else
                return value.ToString();
        }
        //convert string to double;
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            _strCache = (string)value;
            _dCache = double.Parse(_strCache);
            return _dCache;
        }
    }
//below is codebehind usage:
        Binding bd = new Binding(path);
        bd.Converter = new double2txtConverter();
        bd.Source = source;
        bd.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        txtTarget.SetBinding(TextBox.TextProperty, bd);

0
投票

我根据上面Herm的回答给出答案。解释是正确的,但在控制上使用

Delay
并不能完全解决问题。如果最终用户输入0.005,则需要的延迟会更多,否则它将重新写入值为0。

相反,使用字符串属性进行绑定并尝试将其解析为双倍,并根据解析输出设置您需要的 long 值。在设置值之前进行您需要的所有类型的验证

private double _amount;
private string _amountString;
public string Amount
{
    get { return _amountString;}
    set {
            double d=0;
            if(Double.TryParse(value, out d))
            {
                _amountString=value;
                _amount=d;
            }
        }
   }
}

0
投票

在属性使用的绑定中,

UpdateSourceTrigger=LostFocus
。一旦文本框失去焦点,它将更新属性。


0
投票

我通过附加属性解决了这个问题。

    public class DoubleTextBox : TextBox
    {
        public string DoubleText
        {
            get => (string)GetValue(DoubleTextProperty);
            set => SetValue(DoubleTextProperty, value);
        }
        public static readonly DependencyProperty DoubleTextProperty =
              DependencyProperty.Register(
                  nameof(DoubleText),
                  typeof(string),
                  typeof(DoubleTextBox),
                  new FrameworkPropertyMetadata(
                      string.Empty,
                      FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
                      new PropertyChangedCallback(OnDoubleTextChanged),
                      null,
                      true,
                      UpdateSourceTrigger.LostFocus));
    
        private static void OnDoubleTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is TextBox textBox)
            {
                var currentText = textBox.Text;
                var newText = (string)e.NewValue;
                if (currentText == newText)
                    return;
                if (
                    double.TryParse(currentText, out var currentDouble) &&
                    double.TryParse(newText, out var newDouble) &&
                    currentDouble == newDouble
                    )
                    return;
    
                textBox.Text = newText;
            }
        }
    
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);
            this.DoubleText = this.Text;
        }
    }

用途:

<myControl:DoubleTextBox DoubleText="{Binding Double1, UpdateSourceTrigger=PropertyChanged}" />
© www.soinside.com 2019 - 2024. All rights reserved.