2017-03-31 10 views
6

फिलहाल मेरे पास ग्रिड है और मैं सत्यापन नियमों के साथ एक सेल रखने की कोशिश कर रहा हूं। इसे सत्यापित करने के लिए, मुझे पंक्ति के न्यूनतम और अधिकतम मान की आवश्यकता है।प्रमाणीकरण नियम और निर्भरता संपत्ति के साथ डब्ल्यूपीएफ ग्रिड

मान्यता कक्षा:

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 कक्षा:

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

मैं इस समाधान यहाँ WPF ValidationRule with dependency property और यह बहुत अच्छा काम करता है की कोशिश की है। लेकिन अब मैं इस मुद्दे पर आया हूं कि प्रॉक्सी को व्यूमोडेल के माध्यम से तुरंत चालू नहीं किया जा सकता है। यह पंक्ति के चयनित कॉम्बोबॉक्स वैल्यू मिन और मैक्स प्रॉपर्टी पर आधारित है।

उदाहरण के लिए, कि कॉम्बो बॉक्स नमूना मूल्यों नीचे

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

एक ग्रिड लगभग के रूप में कई पंक्तियों हो सकता है के बाद से के रूप में यह चाहता है, मैं नहीं देख सकते हैं कि बनाने प्रॉक्सी मेरी स्थिति में काम करेगा कर रहे हैं। अगर मैं मार्गदर्शन के कुछ सुझाव प्राप्त कर सकता हूं, तो इसकी सराहना की जाएगी।

+0

आपके कोड में केवल एक 'कॉम्बोबॉक्स' है। – AnjumSKhan

+0

@AjjumSKhan केवल एक कॉम्बोबॉक्स होने का अनुमान है। कॉम्बोबॉक्स मान प्रकार फीट टाइप प्रकार के हैं। तो जो भी चुना गया है यह निर्धारित करता है कि यह न्यूनतम और अधिकतम है। – Master

+4

क्या आप वाकई हैं कि यह एक [XY समस्या] नहीं है (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)? यह 'सत्यापनकरण' का उपयोग करके ऐसा करने के लिए बहुत प्रयास करने जा रहा है, जबकि यदि आप दृश्य-तर्क में सत्यापन तर्क को स्थानांतरित करते हैं तो यह पूरा करना आसान होगा। – 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", }, 
    }; 
} 

यह एक एकल ग्रिड पंक्ति के लिए ViewModel है:

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 साथ यह परीक्षण किया है, लेकिन परिणाम होना चाहिए एक ही:

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

एक FeeType उदाहरण Min और Max रनटाइम पर संशोधित कर सकते हैं, तो आप लागू करने की आवश्यकता INotifyPropertyChanged उस वर्ग पर भी, मूल्य परिवर्तन को उचित रूप से प्रबंधित करते हैं।

तो आप चीजों को "MVVM" के लिए नए हैं, "ViewModels", "अधिसूचना में परिवर्तन" आदि, this article को एक नज़र दे। यदि आप आमतौर पर डब्ल्यूपीएफ पर मध्यम-बड़े प्रोजेक्ट पर काम करते हैं, तो एमवीवीएम पैटर्न के माध्यम से व्यू और लॉजिक को कम करने के तरीके सीखना उचित है। यह आपको तर्क को तेजी से और अधिक स्वचालित तरीके से परीक्षण करने और चीजों को संगठित और केंद्रित रखने की अनुमति देता है।

+0

हालांकि इस विशेष उदाहरण में इसकी आवश्यकता नहीं हो सकती है, लेकिन 'INotifyDataErrorInfo.ErrorsChanged' ईवेंट को बढ़ाने के लिए भी अच्छा अभ्यास होगा। – Grx70

+0

@ Grx70, ठीक है, वास्तव में, डब्ल्यूपीएफ को आपको सरल परिदृश्यों में 'त्रुटियों की घटना' घटना को बढ़ाने की आवश्यकता नहीं है: जब 'PropertyChanged' ईवेंट उठाया जाता है तो यह त्रुटियों को दोबारा जांचता है। यदि आप मेरे कोड को वीएस समाधान में कॉपी करते हैं और इसे चलाते हैं तो आप इसे देख सकते हैं। 'त्रुटियों को बदलना 'घटना केवल जटिल परिस्थितियों में उपयोगी है, और चूंकि मेरा कोड पहले से ही लंबा था, इसलिए मैं इसे किसी मुद्दे को पूरा करने के लिए और अधिक समय तक नहीं बनाना चाहता था, जिसमें यह मामला केवल सैद्धांतिक है। –

संबंधित मुद्दे