[Wpf] 유효성 검사를 사용하여 이중 필드에 바인딩


Answers

내가 파티에 좀 늦었다는 것을 알았지 만,이 문제에 대한 오히려 깨끗한 해결책을 찾았다.

double로 변환 된 마지막 문자열을 기억하고 존재하는 경우 반환하는 영리한 변환기는 원하는 모든 작업을 수행해야합니다.

사용자가 텍스트 상자의 내용을 변경하면 ConvertBack은 사용자가 입력 한 문자열을 저장하고 문자열을 구문 분석하여 해당 값을 뷰 모델에 전달합니다. 직후에 Convert가 호출되어 새로 변경된 값을 표시합니다. 이 시점에서 저장된 문자열은 null이 아니므로 반환됩니다.

사용자가 아닌 응용 프로그램에서 이중 변환 만 수행하면 변환이 호출됩니다. 즉, 캐시 된 문자열은 null이되고 표준 ToString ()은 double에 대해 호출됩니다.

이런 식으로 사용자는 텍스트 상자의 내용을 수정할 때 이상한 일이 일어나지 않도록하지만 응용 프로그램은 여전히 ​​변경을 트리거 할 수 있습니다.

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

UpdateSourceTrigger=PropertyChanged 하여 TextBox 를 일부 객체의 double 속성에 바인딩하려고합니다. 목표는 입력 된 값의 유효성을 허용 범위 내로 바로 편집하는 것입니다 (그렇지 않은 경우 오류를 표시합니다). IDataErrorInfo 를 통해 모델 레벨에서 유효성 검사를 구현하고 싶습니다.

모든 속성은 int 속성에 바인딩 할 때 좋지만 속성이 두 배이면 좌절하는 편집 동작이 나타납니다. 마지막 소수점 이하 자릿수를 지운 후에 - 소수점 구분 기호가 자동으로 지워집니다 (가능한 모든 소수점 이하 자릿수로). 예를 들어, 숫자 '12 .03 '에서 숫자'3 '을 지운 후에 텍스트는 '12 .0'대신 '12'로 변경됩니다.

도와주세요.

샘플 코드는 다음과 같습니다.

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>

MainWindow.xaml.cs :

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

    public MainWindow()
    {
      InitializeComponent();
      DataContext = _uiData;
    }
  }
}

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



float 값을 텍스트 상자에 바인딩하는 동작이 .NET 4에서 4.5로 변경되었습니다. .NET 4.5에서는 기본적으로 'UpdateSourceTrigger = PropertyChanged'를 사용하여 구분 문자 (쉼표 또는 점)를 입력 할 수 없습니다.

마이크로 소프트가 말하길, 이것은 의도 된 것이다.

여전히 'UpdateSourceTrigger = PropertyChanged'를 사용하려는 경우 App.xaml.cs 생성자에 다음 코드 줄을 추가하여 .NET 4.5 응용 프로그램에서 .NET 4 동작을 강제로 수행 할 수 있습니다.

public App()  
{
    System.Windows.FrameworkCompatibilityPreferences
               .KeepTextBoxDisplaySynchronizedWithTextProperty = false;   
}

(Sebastian Lux - 여기 에서 그대로 복사)




문제는 값이 변경 될 때마다 속성을 업데이트한다는 것입니다. 12.03을 12.0으로 변경하면 12로 반올림됩니다.

xaml 에서 TextBox 를 변경하여 delay 을 제공함으로써 변경 사항을 확인할 수 있습니다.

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,Delay=500, ValidatesOnDataErrors=True}">

delay 은 밀리 초 단위의 지연 시간 후에 속성을 통지하고 설정합니다. 이처럼 StringFormat 사용하는 것이 더 낫다.

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged,StringFormat=N2, ValidatesOnDataErrors=True}">



동일한 문제가 발생하여 아주 간단한 해결책을 찾았습니다 : 사용자 정의 유효성 검사기를 사용하십시오.이 유효성 검사기는 텍스트가 "."로 끝나면 "유효"를 반환하지 않습니다. 또는 "0":

double val = 0;
string tmp = value.ToString();

if (tmp.EndsWith(",") || tmp.EndsWith("0") || tmp.EndsWith("."))
{
    return new ValidationResult(false, "Enter another digit, or delete the last one.");
}
else
{
    return ValidationResult.ValidResult;
}



소문자로 값의 서식을 지정하려고 시도 했습니까?

이상하게 보일지 모르지만, 항상 소수점 이하 N 자리를 가질 것입니다.

<TextBox.Text>
    <Binding Path="DoubleField" StringFormat="{}{0:0.00}" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"/>
</TextBox.Text>

고정 소수점 자리가 충분하지 않은 경우 값을 문자열로 처리하고이를 이중으로 변환하는 변환기를 작성해야 할 수 있습니다.




바인딩에서 StringFormat을 사용해보십시오.

<TextBox Width="100" Margin="10" Text="{Binding DoubleField, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat='0.0'}"> 

문자열 형식이 맞는지 잘 모르겠지만 잠시 동안 한 번도 해본 적이 없지만 예제 일뿐입니다.