2017-03-31 11 views
6

현재 그리드가 있으며 유효성 검사 규칙이있는 셀이 있습니다. 유효성을 검사하려면 행의 최소값과 최대 값이 필요합니다.유효성 검사 규칙 및 종속성 속성이있는 WPF 격자

검증 클래스 :

public decimal Max { get; set; } 

public decimal Min { get; set; } 

public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) 
{ 
    var test = i < Min; 
    var test2 = i > Max; 

    if (test || test2) 
     return new ValidationResult(false, String.Format("Fee out of range Min: ${0} Max: ${1}", Min, Max)); 
    else 
     return new ValidationResult(true, null); 
} 

사용자 제어 :

<telerik:RadGridView SelectedItem ="{Binding SelectedScript}" 
        ItemsSource="{Binding ScheduleScripts}"> 
    <telerik:RadGridView.Columns> 
     <telerik:GridViewDataColumn 
      DataMemberBinding="{Binding Amount}" Header="Amount" 
      CellTemplate="{StaticResource AmountDataTemplate}" 
      CellEditTemplate="{StaticResource AmountDataTemplate}"/> 
     <telerik:GridViewComboBoxColumn 
      Header="Fee Type" 
      Style="{StaticResource FeeTypeScriptStyle}" 
      CellTemplate="{StaticResource FeeTypeTemplate}"/>   
    </telerik:RadGridView.Columns> 
</telerik:RadGridView> 

FeeType 클래스 : 여기 WPF ValidationRule with dependency property하고 좋은 작품을이 솔루션을 시도했습니다

public class FeeType 
{ 
    public decimal Min { get; set; } 
    public decimal Max { get; set; } 
    public string Name { get; set; } 
} 

. 하지만 이제는 뷰 모델을 통해 프록시를 인스턴스화 할 수 없다는 문제가 발생했습니다. 그것은 행의 선택된 ComboBox Value의 Min 및 Max 속성을 기반으로합니다.

예를 들어, 그 콤보 상자의 샘플 값은 원하는대로 그리드 사실상 많은 행이있을 수 있기 때문에

Admin Min: $75 Max $500 
Late Min: $0 Max $50 

아래, 내가 만드는 프록시 내 상황에서 어떻게 작동하는지 볼 수 있습니다. 가이드의 일부 팁을 얻을 수 있다면 크게 감사하겠습니다.

+0

코드에 'ComboBox'가 하나만 있습니다. – AnjumSKhan

+0

@AnjumSKhan 하나의 ComboBox 만 있다고 가정합니다. comboBox 값은 FeeType 클래스 유형입니다. 따라서 선택되는 것이 무엇이든간에 최소 및 최대가 결정됩니다. – Master

+4

이것이 [XY 문제] (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)가 아니라고 확신합니까? ValidationRule을 사용하여이 작업을 수행하는 데 많은 노력을 기울일 것입니다. 반면에 유효성 검사 로직을 뷰 모델로 이동하면 쉽게 수행 할 수 있습니다. – Grx70

답변

4

경고 : 이것은 최종 수정 솔루션이 아니지만 유효성 검증 로직을 구현하여 ViewModels에 완전히 적용하는 올바른 방법을 보여줍니다.

public class FeeType 
{ 
    public decimal Min { get; set; } 
    public decimal Max { get; set; } 
    public string Name { get; set; } 

    public static readonly FeeType[] List = new[] 
    { 
     new FeeType { Min = 0, Max = 10, Name = "Type1", }, 
     new FeeType { Min = 2, Max = 20, Name = "Type2", }, 
    }; 
} 

이 하나의 그리드 행의 뷰 모델입니다 :

는 semplicity의 목적을 위해, 나는 FeeType 클래스의 정적 속성과 FeeTypes의 목록을 만들 수 있습니다. 나는 금액과 수수료 속성 만 넣는다.

public class RowViewModel : INotifyPropertyChanged, INotifyDataErrorInfo 
{ 
    public RowViewModel() 
    { 
     _errorFromProperty = new Dictionary<string, string> 
     { 
      { nameof(Fee), null }, 
      { nameof(Amount), null }, 
     }; 

     PropertyChanged += OnPropertyChanged; 
    } 

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     switch(e.PropertyName) 
     { 
      case nameof(Fee): 
       OnFeePropertyChanged(); 
       break; 
      case nameof(Amount): 
       OnAmountPropertyChanged(); 
       break; 
      default: 
       break; 
     } 
    } 

    private void OnFeePropertyChanged() 
    { 
     if (Fee == null) 
      _errorFromProperty[nameof(Fee)] = "You must select a Fee!"; 
     else 
      _errorFromProperty[nameof(Fee)] = null; 

     NotifyPropertyChanged(nameof(Amount)); 
    } 

    private void OnAmountPropertyChanged() 
    { 
     if (Fee == null) 
      return; 

     if (Amount < Fee.Min || Amount > Fee.Max) 
      _errorFromProperty[nameof(Amount)] = $"Amount must be between {Fee.Min} and {Fee.Max}!"; 
     else 
      _errorFromProperty[nameof(Amount)] = null; 
    } 

    public decimal Amount 
    { 
     get { return _Amount; } 
     set 
     { 
      if (_Amount != value) 
      { 
       _Amount = value; 
       NotifyPropertyChanged(); 
      } 
     } 
    } 
    private decimal _Amount; 

    public FeeType Fee 
    { 
     get { return _Fee; } 
     set 
     { 
      if (_Fee != value) 
      { 
       _Fee = value; 
       NotifyPropertyChanged(); 
      } 
     } 
    } 
    private FeeType _Fee; 

    #region INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 
    public void NotifyPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    #endregion 

    #region INotifyDataErrorInfo 
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; 

    public bool HasErrors 
    { 
     get 
     { 
      return _errorFromProperty.Values.Any(x => x != null); 
     } 
    } 

    public IEnumerable GetErrors(string propertyName) 
    { 
     if (string.IsNullOrEmpty(propertyName)) 
      return _errorFromProperty.Values; 

     else if (_errorFromProperty.ContainsKey(propertyName)) 
     { 
      if (_errorFromProperty[propertyName] == null) 
       return null; 
      else 
       return new[] { _errorFromProperty[propertyName] }; 
     } 

     else 
      return null; 
    } 

    private Dictionary<string, string> _errorFromProperty; 
    #endregion 
} 

지금 Telerik에서 같은 나는 기본 DataGrid로 테스트하지만, 결과는해야하십시오 FeeType 인스턴스가 런타임에 MinMax을 수정할 수 있다면

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Rows}"> 
    <DataGrid.Columns> 
    <DataGridTextColumn Binding="{Binding Amount}"/> 
    <DataGridComboBoxColumn SelectedItemBinding="{Binding Fee, UpdateSourceTrigger=PropertyChanged}" 
          ItemsSource="{x:Static local:FeeType.List}" 
          DisplayMemberPath="Name" 
          Width="200"/> 
    </DataGrid.Columns> 
</DataGrid> 

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     Rows = new List<RowViewModel> 
     { 
      new RowViewModel(), 
      new RowViewModel(), 
     }; 

     DataContext = this; 
    } 

    public List<RowViewModel> Rows { get; } 
} 

, 구현해야 해당 클래스의 INotifyPropertyChanged도 값 처리가 적절하게 변경됩니다.

"MVVM", "ViewModels", "Notification changes" 등을 처음 접하는 경우 this article을 살펴보십시오. 보통 WPF의 중간 규모 프로젝트에서 작업하는 경우 MVVM 패턴을 통해 뷰와 로직을 분리하는 방법을 배우는 것이 좋습니다. 이를 통해보다 빠르고 자동화 된 방식으로 논리를 테스트 할 수 있으며, 모든 것을 정리하고 집중시킬 수 있습니다.

+0

이 특정 예에서는 필수는 아니지만 INotifyDataErrorInfo.ErrorsChanged 이벤트를 발생시키는 것이 좋습니다. – Grx70

+0

@ Grx70, 글쎄, 실제로 WPF에서는 간단한 시나리오에서'ErrorsChanged' 이벤트를 발생시킬 필요가 없습니다. 즉,'PropertyChanged' 이벤트가 발생할 때 오류를 다시 확인합니다. VS 솔루션에 내 코드를 복사하여 실행하면이를 볼 수 있습니다. 'ErrorsChanged' 이벤트를 발생시키는 것은 더 복잡한 시나리오에서만 유용합니다. 코드가 이미 길었 기 때문에이 경우 _가 이론적 인 문제를 수행하는 데 더 오래 걸리지 않으려했습니다. –