通过验证绑定到双字段

aru*_*doy 16 wpf binding

我试图绑定TextBoxdouble一些对象的属性UpdateSourceTrigger=PropertyChanged.目标是在编辑期间立即验证输入的值是否在允许的范围内(如果没有则显示错误).我想在Model级别上实现验证,即通过IDataErrorInfo.

当我绑定到int属性时,所有工作都很好,但如果属性为double,则会出现令人沮丧的编辑行为:在删除数字的小数部分中的最后一个有效数字后 - 小数分隔符将自动擦除(包含所有可能的小数零).例如,在从数字'12 .03'中删除数字'3'之后,文本被改为'12'而不是'12 .0'.

请帮忙.

以下是示例代码:

MainWindow.xaml:

<Window x:Class="BindWithValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="80" Width="200" WindowStartupLocation="CenterOwner">

  <StackPanel>
    <TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
      <TextBox.Style>
        <Style TargetType="TextBox">
          <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
              <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
          </Style.Triggers>
        </Style>
      </TextBox.Style>
    </TextBox>
  </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

MainWindow.xaml.cs:

namespace BindWithValidation
{
  public partial class MainWindow : Window
  {
    private UISimpleData _uiData = new UISimpleData();

    public MainWindow()
    {
      InitializeComponent();
      DataContext = _uiData;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

UISimpleData.cs:

namespace BindWithValidation
{
  public class UISimpleData : INotifyPropertyChanged, IDataErrorInfo
  {
    private double _doubleField = 12.03;

    public double DoubleField
    {
      get
      {
        return _doubleField;
      }
      set
      {
        if (_doubleField == value)
          return;

        _doubleField = value;
        RaisePropertyChanged("DoubleField");
      }
    }

    public string this[string propertyName]
    {
      get
      {
        string validationResult = null;
        switch (propertyName)
        {
          case "DoubleField":
          {
            if (DoubleField < 2 || DoubleField > 5)
              validationResult = "DoubleField is out of range";
            break;
          }

          default:
            throw new ApplicationException("Unknown Property being validated on UIData");
        }

        return validationResult;
      }
    }

    public string Error { get { return "not implemented"; } }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string property)
    {
      if ( PropertyChanged != null )
        PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Jas*_*ere 10

我意识到我有点迟到了,但我找到了一个(我认为)相当干净的解决方案.

一个聪明的转换器,它记住转换为double的最后一个字符串并返回它(如果它存在)应该做你想要的一切.

请注意,当用户更改文本框的内容时,ConvertBack将存储用户输入的字符串,解析字符串以获取double,并将该值传递给视图模型.紧接着,调用Convert来显示新更改的值.此时,存储的字符串不为null,将返回.

如果应用程序而不是用户导致double更改,则仅调用Convert.这意味着缓存的字符串将为null,并且将在double上调用标准ToString().

通过这种方式,用户在修改文本框的内容时避免了奇怪的意外,但应用程序仍然可以触发更改.

public class DoubleToPersistantStringConverter : IValueConverter
{
    private string lastConvertBackString;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is double)) return null;

        var stringValue = lastConvertBackString ?? value.ToString();
        lastConvertBackString = null;

        return stringValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is string)) return null;

        double result;
        if (double.TryParse((string)value, out result))
        {
            lastConvertBackString = (string)value;
            return result;
        }

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案。但是,使用此转换器在多个文本框上同时调用NotifyPropertyChanged时,会使事情变得混乱。我建议将属性作为转换器的参数传递,并用`Dictionary &lt;String,String&gt;`代替`lastConvertBackString`。这样,您可以记住每个属性的最后一个字符串。 (2认同)

Ben*_*jol 9

将浮点值绑定到文本框的行为已从.NET 4更改为4.5.使用.NET 4.5,默认情况下不再可以使用"UpdateSourceTrigger = PropertyChanged"输入分隔符(逗号或点).

微软表示,这是有意的

如果您仍想使用"UpdateSourceTrigger = PropertyChanged",则可以通过将以下代码行添加到以下构造函数中来强制.NET 4.5应用程序中的.NET 4行为App.xaml.cs:

public App()  
{
    System.Windows.FrameworkCompatibilityPreferences
               .KeepTextBoxDisplaySynchronizedWithTextProperty = false;   
}
Run Code Online (Sandbox Code Playgroud)

(塞巴斯蒂安·勒克斯 - 从这里逐字复制)


Cha*_*leh 1

尝试在绑定上使用 StringFormat:

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat='0.0'}"> 
Run Code Online (Sandbox Code Playgroud)

不确定该字符串格式是否正确,因为我有一段时间没有这样做了,但这只是一个例子