2010-10-05 20 views
13

साथ WPF ValidationRule मान लीजिए आप एक वर्ग ValidationRule से इनहेरिट है:निर्भरता संपत्ति

public class MyValidationRule : ValidationRule 
{ 
    public string ValidationType { get; set; } 

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) 
    {} 
} 

XAML में आप इस तरह मान्य कर रहे हैं:

<ComboBox.SelectedItem> 
    <Binding Path="MyPath" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True"> 
     <Binding.ValidationRules> 
      <qmvalidation:MyValidationRule ValidationType="notnull"/> 
     </Binding.ValidationRules> 
    </Binding> 
</ComboBox.SelectedItem> 

कौन सा काम करता है और सब कुछ ठीक है।

लेकिन अब मान लीजिए, आप ValidationType="{Binding MyBinding}" चाहते हैं जहां MyBindingDataContext से आता है।

इस उद्देश्य के MyValidationRule एक DependencyObject के रूप में बनाने के लिए और एक निर्भरता संपत्ति जोड़ने के लिए मैं की आवश्यकता होगी के लिए

मैंने DependencyObject पर एक कक्षा लिखने की कोशिश की है, और इसे बांधें। हालांकि 2 समस्याएं हैं .. ValidationRule में Combobox/Item से DataContext नहीं है।

क्या आपके पास कोई विचार है, इसे कैसे हल करें?

धन्यवाद!

उत्तर

14

ValidationRuleDependencyObject से प्राप्त नहीं होता है, तो आप अपनी कस्टम सत्यापन कक्षा में DependecyProperty नहीं बना सकते हैं।

हालांकि के रूप में this link में विस्तार से बताया है कि आप अपने मान्यता कक्षा में एक सामान्य संपत्ति एक प्रकार है कि DependecyObject से इनहेरिट की है जो है और वह कक्षा में एक DependencyProperty बना सकते हैं।

public class ComparisonValue : DependencyObject 
{ 
    public int Value 
    { 
     get { return (int)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
     nameof(Value), 
     typeof(int), 
     typeof(ComparisonValue), 
     new PropertyMetadata(default(int)); 

इस का हल:

[ContentProperty("ComparisonValue")] 
public class GreaterThanValidationRule : ValidationRule 
{ 
    public ComparisonValue ComparisonValue { get; set; } 

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) 
    { 
     string s = value?.ToString(); 
     int number; 

     if (!Int32.TryParse(s, out number)) 
     { 
      return new ValidationResult(false, "Not a valid entry"); 
     } 

     if (number <= ComparisonValue.Value) 
     { 
      return new ValidationResult(false, $"Number should be greater than {ComparisonValue}"); 
     } 

     return ValidationResult.ValidResult; 
    } 
} 

ComparisonValue एक साधारण वर्ग कि DependencyObject से विरासत और एक DependencyProperty है:

उदाहरण यहां के लिए एक कस्टम ValidationRule वर्ग कि bindable संपत्ति का समर्थन है मूल समस्या लेकिन दुर्भाग्य से दो और समस्याएं लाती हैं:

  1. बाइंडिंग सही ढंग से काम नहीं करती है क्योंकि ValidationRules दृश्य पेड़ का हिस्सा नहीं है और इसलिए बाध्य संपत्ति सही ढंग से नहीं मिल सकती है।उदाहरण के लिए इस अनुभवहीन दृष्टिकोण काम नहीं करेगा:

    <TextBox Name="TextBoxToValidate"> 
        <TextBox.Text> 
         <Binding Path="ViewModelProperty" UpdateSourceTrigger="PropertyChanged"> 
          <Binding.ValidationRules> 
           <numbers:GreaterThanValidationRule> 
            <numbers:ComparisonValue Value="{Binding Text, ElementName=TextBoxToValidate}"/> 
           </numbers:GreaterThanValidationRule> 
          </Binding.ValidationRules> 
         </Binding> 
        </TextBox.Text> 
    </TextBox> 
    

    इसके बजाय एक प्रॉक्सी वस्तु इस्तेमाल किया जाना चाहिए के रूप में this जवाब में विस्तार से बताया:

    public class BindingProxy : Freezable 
    { 
        protected override Freezable CreateInstanceCore() 
        { 
         return new BindingProxy(); 
        } 
    
        public object Data 
        { 
         get { return GetValue(DataProperty); } 
         set { SetValue(DataProperty, value); } 
        } 
        public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data), typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); 
    } 
    
:

<TextBox Name="TextBoxToValidate"> 
    <TextBox.Resources> 
     <bindingExtensions:BindingProxy x:Key="TargetProxy" Data="{Binding Path=Text, ElementName=TextBoxToValidate}"/> 
    </TextBox.Resources> 
    <TextBox.Text> 
     <Binding Path="ViewModelProperty" UpdateSourceTrigger="PropertyChanged"> 
      <Binding.ValidationRules> 
       <numbers:GreaterThanValidationRule> 
        <numbers:ComparisonValue Value="{Binding Data, Source={StaticResource TargetProxy}}"/> 
       </numbers:GreaterThanValidationRule> 
      </Binding.ValidationRules> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 

BindingProxy एक साधारण वर्ग है


  1. यदि कस्टम ValidationRule में संपत्ति किसी अन्य ऑब्जेक्ट की संपत्ति से जुड़ी है, तो मूल संपत्ति के लिए सत्यापन तर्क तब नहीं होगा जब उस अन्य ऑब्जेक्ट की संपत्ति में परिवर्तन हो।

    इस समस्या को हल करने के लिए हमें बाध्यकारी अद्यतन करना चाहिए जब ValidationRule की बाध्य संपत्ति अद्यतन हो। सबसे पहले हमें उस संपत्ति को हमारे ComparisonValue कक्षा में बांधना चाहिए।

    public class ComparisonValue : DependencyObject 
    { 
        public int Value 
        { 
         get { return (int)GetValue(ValueProperty); } 
         set { SetValue(ValueProperty, value); } 
        } 
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
         nameof(Value), 
         typeof(int), 
         typeof(ComparisonValue), 
         new PropertyMetadata(default(int), OnValueChanged)); 
    
        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
         ComparisonValue comparisonValue = (ComparisonValue) d; 
         BindingExpressionBase bindingExpressionBase = BindingOperations.GetBindingExpressionBase(comparisonValue, BindingToTriggerProperty); 
         bindingExpressionBase?.UpdateSource(); 
        } 
    
        public object BindingToTrigger 
        { 
         get { return GetValue(BindingToTriggerProperty); } 
         set { SetValue(BindingToTriggerProperty, value); } 
        } 
        public static readonly DependencyProperty BindingToTriggerProperty = DependencyProperty.Register(
         nameof(BindingToTrigger), 
         typeof(object), 
         typeof(ComparisonValue), 
         new FrameworkPropertyMetadata(default(object), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 
    } 
    

    पहले मामले में एक ही प्रॉक्सी समस्या भी यहां मौजूद है: फिर, हम बंधन जब Value गुण परिवर्तन के स्रोत अद्यतन कर सकते हैं। इस मामले TextBoxToValidate की Text संपत्ति SomeCollection की Items.Count संपत्ति के खिलाफ मान्य है में

    <ItemsControl Name="SomeCollection" ItemsSource="{Binding ViewModelCollectionSource}"/> 
    
    <TextBox Name="TextBoxToValidate"> 
        <TextBox.Resources> 
         <bindingExtensions:BindingProxy x:Key="TargetProxy" Data="{Binding Path=Items.Count, ElementName=SomeCollection}"/> 
         <bindingExtensions:BindingProxy x:Key="SourceProxy" Data="{Binding Path=Text, ElementName=TextBoxToValidate, Mode=TwoWay}"/> 
        </TextBox.Resources> 
        <TextBox.Text> 
         <Binding Path="ViewModelProperty" UpdateSourceTrigger="PropertyChanged"> 
          <Binding.ValidationRules> 
           <numbers:GreaterThanValidationRule> 
            <numbers:ComparisonValue Value="{Binding Data, Source={StaticResource TargetProxy}}" BindingToTrigger="{Binding Data, Source={StaticResource SourceProxy}}"/> 
           </numbers:GreaterThanValidationRule> 
          </Binding.ValidationRules> 
         </Binding> 
        </TextBox.Text> 
    </TextBox> 
    

    : इसलिए हम एक और प्रॉक्सी वस्तु बनाना चाहिए। जब सूची में आइटमों की संख्या बदल जाती है, तो Text संपत्ति के लिए सत्यापन ट्रिगर किया जाएगा।

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