WPF मान्यता त्रुटियों का पता लगाना


115

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

मान लीजिए कि आपके पास इस तरह से नियंत्रणों का एक समूह है और आपके पास एक सेव बटन है। जब उपयोगकर्ता सहेजें बटन पर क्लिक करता है, तो आपको यह सुनिश्चित करने की आवश्यकता होती है कि बचत के साथ आगे बढ़ने से पहले कोई सत्यापन त्रुटियां नहीं हैं। यदि सत्यापन त्रुटियां हैं, तो आप उन पर रोक लगाना चाहते हैं।

WPF में, आपको कैसे पता चलता है कि आपके किसी भी डेटा बाउंड कंट्रोल में वेलिडेशन एरर सेट हैं?

जवाबों:


137

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

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

1
मुझे यह विशेष समाधान बहुत पसंद है!
क्राइस्टोफैड

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

वहाँ केवल उन DependencyObjects जो एक विशेष DataContext के लिए बाध्य कर रहे थे मानने के लिए कोई रास्ता नहीं है? मुझे ट्रेवेल का विचार पसंद नहीं है। किसी विशेष डेटा स्रोत से जुड़े बाइंडिंग का एक संग्रह हो सकता है।
ZAB

5
बस सोच रहा था, आप IsValidफ़ंक्शन को कैसे कहते हैं? मुझे CanExecuteलगता है कि आपने सेट किया है जो मुझे लगता है कि सेव बटन के कमांड से संबंधित है। अगर मैं कमांड का उपयोग नहीं कर रहा हूं तो क्या यह काम करेगा? और बटन अन्य नियंत्रणों से किस प्रकार संबंधित है जिसे जाँचने की आवश्यकता है? मेरा एकमात्र विचार यह है कि इसे कैसे उपयोग किया जाए IsValid, प्रत्येक नियंत्रण के लिए कॉल करके जिसे मान्य किया जाना है। संपादित करें: ऐसा लगता है कि आप उसे सत्यापित कर रहे हैं senderजिसकी मुझे बचत बटन होने की उम्मीद है। यह मुझे सही नहीं लगता है।
निकोलस मिलर

1
@ निक मिलर Windowभी एक निर्भरता वस्तु है। मैं शायद वह किसी तरह के इवेंट हैंडलर के साथ इसे स्थापित कर रहा हूं Window। वैकल्पिक रूप से, आप इसे कक्षा IsValid(this)से सीधे कॉल कर सकते हैं Window
एकमुश्त

47

निम्नलिखित कोड (क्रिस बेचने और आयन ग्रिफ़िथ द्वारा प्रोग्रामिंग 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
   {

    ....
   }
}

33

लिस्टबॉक्स का उपयोग करते समय पोस्ट किए गए कोड ने मेरे लिए काम नहीं किया। मैंने इसे फिर से लिखा और अब यह काम करता है:

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
मेरे आइटम्सकंट्रोल पर काम करने के लिए अपने समाधान के लिए वोट करें।
जेफ टी।

1
मैं इस समाधान का उपयोग यह जांचने के लिए कर रहा हूं कि मेरे डेटाग्रिड में सत्यापन त्रुटियां हैं या नहीं। हालाँकि, इस पद्धति को मेरी व्यूअमॉडल कमांड केनेक्स्ट्यूट विधि कहा जाता है, और मुझे लगता है कि दृश्य पेड़ की वस्तुओं तक पहुंचना किसी तरह MVVM संरक्षक का उल्लंघन करता है, क्या आप नहीं? कोई विकल्प?
इगोर कोंड्रासोवस 15

16

एक ही समस्या थी और प्रदान किए गए समाधानों की कोशिश की। H-Man2's और skiba_k के समाधानों के संयोजन ने मेरे लिए लगभग ठीक काम किया, एक अपवाद के लिए: मेरी विंडो में एक Tabontontrol है। और सत्यापन नियम केवल तबितेम के लिए मूल्यांकन किए जाते हैं जो वर्तमान में दिखाई देते हैं। इसलिए मैंने 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;
    }

7

डीन के महान LINQ-कार्यान्वयन के अलावा, मुझे डिपेंडेंसीओबजेक्ट्स के लिए कोड को विस्तार में रखने में मज़ा आया:

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

यह पुनर्जन्म को देखते हुए इसे बहुत अच्छा बनाता है।


2

मैं एक छोटे से अनुकूलन की पेशकश करूंगा।

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


2

यहाँ WPF में फॉर्म सत्यापन के लिए एक पुस्तकालय हैयहां नौगट पैकेज

नमूना:

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

0

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

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


0

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


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;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.