2008-09-24 20 views
104

डब्ल्यूपीएफ में आप ExceptionValidationRule या DataErrorValidationRule का उपयोग कर डेटा बाइंडिंग के दौरान अपने डेटा लेयर में फेंकने वाली त्रुटियों के आधार पर सत्यापन सेट कर सकते हैं।डब्ल्यूपीएफ सत्यापन त्रुटियों का पता लगाना

मान लें कि आपके पास इस तरह से स्थापित नियंत्रणों का एक गुच्छा था और आपके पास एक सहेजें बटन था। जब उपयोगकर्ता सहेजें बटन पर क्लिक करता है, तो आपको यह सुनिश्चित करना होगा कि सहेजने से पहले कोई सत्यापन त्रुटियां न हों। अगर सत्यापन त्रुटियां हैं, तो आप उन पर हॉलर करना चाहते हैं।

डब्ल्यूपीएफ में, आप कैसे पता लगाते हैं कि आपके डेटा बाउंड नियंत्रण में से कोई भी सत्यापन त्रुटियों को सेट करता है या नहीं?

उत्तर

127

यह पोस्ट बेहद सहायक था। योगदान देने वाले सभी लोगों का शुक्रिया। यहां एक LINQ संस्करण है जिसे आप या तो प्यार करेंगे या नफरत करेंगे।

public static bool IsValid(this DependencyObject instance) 
{ 
    // Validate recursivly 
    return !Validation.GetHasError(instance) && LogicalTreeHelper.GetChildren(instance).OfType<DependencyObject>().All(child => child.IsValid()); 
} 

यह यह बहुत अच्छा विचार reuseablity बनाता है:

private void CanExecute(object sender, CanExecuteRoutedEventArgs e) 
{ 
    e.CanExecute = IsValid(sender as DependencyObject); 
} 

private bool IsValid(DependencyObject obj) 
{ 
    // The dependency object is valid if it has no errors and all 
    // of its children (that are dependency objects) are error-free. 
    return !Validation.GetHasError(obj) && 
    LogicalTreeHelper.GetChildren(obj) 
    .OfType<DependencyObject>() 
    .All(IsValid); 
} 
+0

मुझे यह विशेष समाधान बहुत पसंद है! – ChristopheD

+0

बस इस धागे पर ठोकर खाई। बहुत उपयोगी छोटे समारोह। धन्यवाद! –

+0

आप ... भयानक हैं !!! –

0

आप अपने सभी नियंत्रण पेड़ को दोबारा शुरू कर सकते हैं और संलग्न संपत्ति सत्यापन की जांच कर सकते हैं। हैसररप्रोपर्टी, फिर उसमें पहली बार ध्यान दें।

आप भी कई पहले से ही लिखा समाधान आप एक उदाहरण के लिए this धागा और अधिक जानकारी की जांच कर सकते उपयोग कर सकते हैं

46

निम्नलिखित कोड (प्रोग्रामिंग WPF किताब से क्रिस द्वारा बेचें & इयान ग्रीफिथ) एक पर सभी बाध्यकारी नियम मान्य करता है निर्भरता वस्तु और उसके बच्चों:

public static class Validator 
{ 

    public static bool IsValid(DependencyObject parent) 
    { 
     // Validate all the bindings on the parent 
     bool valid = true; 
     LocalValueEnumerator localValues = parent.GetLocalValueEnumerator(); 
     while (localValues.MoveNext()) 
     { 
      LocalValueEntry entry = localValues.Current; 
      if (BindingOperations.IsDataBound(parent, entry.Property)) 
      { 
       Binding binding = BindingOperations.GetBinding(parent, entry.Property); 
       foreach (ValidationRule rule in binding.ValidationRules) 
       { 
        ValidationResult result = rule.Validate(parent.GetValue(entry.Property), null); 
        if (!result.IsValid) 
        { 
         BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property); 
         System.Windows.Controls.Validation.MarkInvalid(expression, new ValidationError(rule, expression, result.ErrorContent, null)); 
         valid = false; 
        } 
       } 
      } 
     } 

     // Validate all the bindings on the children 
     for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
      if (!IsValid(child)) { valid = false; } 
     } 

     return valid; 
    } 

} 

आप अपने अपने पेज में इस तरह बटन क्लिक ईवेंट हैंडलर को बचाने/विंडो में यह कॉल कर सकते हैं

private void saveButton_Click(object sender, RoutedEventArgs e) 
{ 

    if (Validator.IsValid(this)) // is valid 
    { 

    .... 
    } 
} 
+1

वाह, यह ठीक काम करता है। यह मुझे बहुत समय बचाता है बहुत बहुत धन्यवाद। – Ewerton

30

पोस्टबॉक्स का उपयोग करते समय पोस्ट कोड मेरे लिए काम नहीं करता था। मैं इसे दुबारा लिखा और अब यह काम करता है: इस सवाल का जवाब रूप aogan में

public static bool IsValid(DependencyObject parent) 
{ 
    if (Validation.GetHasError(parent)) 
     return false; 

    // Validate all the bindings on the children 
    for (int i = 0; i != VisualTreeHelper.GetChildrenCount(parent); ++i) 
    { 
     DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
     if (!IsValid(child)) { return false; } 
    } 

    return true; 
} 
+1

अपने आइटम नियंत्रण पर काम करने के लिए अपने समाधान को वोट दें। –

+0

मैं इस समाधान का उपयोग यह जांचने के लिए कर रहा हूं कि मेरे डेटाग्रिड में सत्यापन त्रुटियां हैं या नहीं। हालांकि, इस विधि को मेरे viewmodel कमांड canexecute विधि पर बुलाया जाता है, और मुझे लगता है कि दृश्य वृक्ष वस्तुओं तक पहुंच किसी भी तरह से एमवीवीएम पटर का उल्लंघन करती है, है ना? कोई विकल्प? –

0

के बजाय स्पष्ट रूप से, सत्यापन नियमों के माध्यम से पुनरावृति बेहतर बस आह्वान expression.UpdateSource():

if (BindingOperations.IsDataBound(parent, entry.Property)) 
{ 
    Binding binding = BindingOperations.GetBinding(parent, entry.Property); 
    if (binding.ValidationRules.Count > 0) 
    { 
     BindingExpression expression 
      = BindingOperations.GetBindingExpression(parent, entry.Property); 
     expression.UpdateSource(); 

     if (expression.HasError) valid = false; 
    } 
} 
15

एक ही समस्या थी और प्रदान की समाधान की कोशिश की। एच-मैन 2 और स्कीबा_के के समाधानों का एक संयोजन मेरे लिए लगभग ठीक काम करता है, एक अपवाद के लिए: मेरी विंडो में टैबकंट्रोल है। और सत्यापन नियमों को केवल टैबआईटम के लिए मूल्यांकन किया जाता है जो वर्तमान में दिखाई दे रहा है। इसलिए मैंने LogicalTreeHelper द्वारा VisualTreeHelper को प्रतिस्थापित किया। अब यह काम कर रहा है।

public static bool IsValid(DependencyObject parent) 
    { 
     // Validate all the bindings on the parent 
     bool valid = true; 
     LocalValueEnumerator localValues = parent.GetLocalValueEnumerator(); 
     while (localValues.MoveNext()) 
     { 
      LocalValueEntry entry = localValues.Current; 
      if (BindingOperations.IsDataBound(parent, entry.Property)) 
      { 
       Binding binding = BindingOperations.GetBinding(parent, entry.Property); 
       if (binding.ValidationRules.Count > 0) 
       { 
        BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property); 
        expression.UpdateSource(); 

        if (expression.HasError) 
        { 
         valid = false; 
        } 
       } 
      } 
     } 

     // Validate all the bindings on the children 
     System.Collections.IEnumerable children = LogicalTreeHelper.GetChildren(parent); 
     foreach (object obj in children) 
     { 
      if (obj is DependencyObject) 
      { 
       DependencyObject child = (DependencyObject)obj; 
       if (!IsValid(child)) { valid = false; } 
      } 
     } 
     return valid; 
    } 
+0

एक अच्छा समाधान ... – ChristopheD

2

मैं एक छोटा अनुकूलन प्रदान करता हूं।

यदि आप एक ही नियंत्रण में कई बार ऐसा करते हैं, तो आप वास्तव में सत्यापन नियमों की नियंत्रण रखने के लिए उपरोक्त कोड जोड़ सकते हैं। फिर जब भी आपको वैधता की जांच करने की आवश्यकता होती है, तो पूरे दृश्य पेड़ की बजाय केवल उन नियंत्रणों पर जाएं। यदि आपके पास ऐसे कई नियंत्रण हैं तो यह बेहतर होगा।

0

आप WPF Application Framework (WAF) की BookLibrary नमूना आवेदन में रुचि हो सकती। यह दिखाता है कि WPF में सत्यापन का उपयोग कैसे करें और सत्यापन त्रुटियों के दौरान सहेजें बटन को कैसे नियंत्रित करें।

7

डीन के महान LINQ कार्यान्वयन के अलावा, मैं मज़ा DependencyObjects के लिए एक एक्सटेंशन में कोड लपेटकर था।

1

WPF में फ़ॉर्म सत्यापन के लिए यहां library है। Nuget package here

नमूना:

<Border BorderBrush="{Binding Path=(validationScope:Scope.HasErrors), 
           Converter={local:BoolToBrushConverter}, 
           ElementName=Form}" 
     BorderThickness="1"> 
    <StackPanel x:Name="Form" validationScope:Scope.ForInputTypes="{x:Static validationScope:InputTypeCollection.Default}"> 
     <TextBox Text="{Binding SomeProperty}" /> 
     <TextBox Text="{Binding SomeOtherProperty}" /> 
    </StackPanel> 
</Border> 

विचार है कि हम संलग्न संपत्ति यह बता इनपुट ट्रैक करने के लिए नियंत्रित करता है के माध्यम से एक सत्यापन दायरे को परिभाषित है। फिर हम कर सकते हैं:

<ItemsControl ItemsSource="{Binding Path=(validationScope:Scope.Errors), 
            ElementName=Form}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate DataType="{x:Type ValidationError}"> 
      <TextBlock Foreground="Red" 
         Text="{Binding ErrorContent}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
संबंधित मुद्दे