WPF-validationserrors erkennen

In WPF können Sie die validation basierend auf Fehlern DataErrorValidationRule während der DataErrorValidationRule mit der ExceptionValidationRule oder DataErrorValidationRule in Ihrer Datenschicht DataErrorValidationRule .

Angenommen, Sie haben eine Reihe von Steuerelementen auf diese Weise eingerichtet und Sie hatten eine Schaltfläche zum Speichern. Wenn der Benutzer auf die Schaltfläche Speichern klickt, müssen Sie sicherstellen, dass keine validationserrors vorliegen, bevor Sie mit dem Speichern fortfahren. Wenn validationserrors auftreten, möchten Sie sie ansprechen.

Wie finden Sie in WPF heraus, ob für einige Ihrer Data-Bound-Steuerelemente validationserrors gesetzt sind?

Solutions Collecting From Web of "WPF-validationserrors erkennen"

Dieser Beitrag war sehr hilfreich. Danke an alle, die dazu beigetragen haben. Hier ist eine LINQ-Version, die Sie entweder lieben oder hassen werden.

 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() .All(IsValid); } 

Der folgende Code (aus Programming WPF Book von Chris Sell & Ian Griffiths) überprüft alle Bindungsregeln für ein Abhängigkeitsobjekt und seine untergeordneten Objekte:

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

Sie können dies in Ihrem Klick-Event-Handler auf diese Weise in Ihrer Seite / Ihrem Fenster aufrufen

 private void saveButton_Click(object sender, RoutedEventArgs e) { if (Validator.IsValid(this)) // is valid { .... } } 

Der gepostete Code funktionierte bei Verwendung einer ListBox nicht. Ich habe es umgeschrieben und jetzt funktioniert es:

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

Hatte das gleiche Problem und probierte die bereitgestellten Lösungen aus. Eine Kombination aus den Lösungen von H-Man2 und skiba_k funktionierte für mich fast perfekt, mit einer Ausnahme: My Window hat ein TabControl. Und die validationsregeln werden nur für das TabItem ausgewertet, das gerade sichtbar ist. Also habe ich VisualTreeHelper durch LogicalTreeHelper ersetzt. Jetzt funktioniert es.

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

Zusätzlich zu der großartigen LINQ-Implementierung von Dean hatte ich Spaß daran, den Code in eine Erweiterung für DependencyObjects einzufügen:

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

Dies macht es sehr nett in Anbetracht der Wiederverwendbarkeit.

Ich würde eine kleine Optimierung anbieten.

Wenn Sie dies mehrmals über die gleichen Steuerelemente tun, können Sie den obigen Code hinzufügen, um eine Liste von Steuerelementen zu erhalten, die tatsächlich über validationsregeln verfügen. Wenn Sie dann nach der Gültigkeit suchen müssen, gehen Sie nur über diese Steuerelemente statt über den gesamten visuellen Baum. Dies würde sich als viel besser erweisen, wenn Sie viele solcher Kontrollen haben.

Hier ist eine Bibliothek für die Formularvalidierung in WPF. Nuget-Paket hier .

Probe:

       

Die Idee ist, dass wir über die angefügte Eigenschaft einen Gültigkeitsbereich definieren, der angibt, welche Eingabesteuerelemente überwacht werden sollen. Dann können wir tun:

        

Sie können die gesamte Struktur Ihrer Steuerelemente rekursiv durchlaufen und die angefügte Eigenschaft Validation.HasErrorProperty überprüfen. Konzentrieren Sie sich dann auf die erste darin enthaltene Eigenschaft.

Sie können auch viele bereits geschriebene Lösungen verwenden. Sie können diesen Thread für ein Beispiel und weitere Informationen überprüfen

Sie könnten an der BookLibrary- Beispielanwendung des WPF Application Framework (WAF) interessiert sein. Es zeigt, wie die validation in WPF verwendet wird und wie die Schaltfläche “Speichern” gesteuert wird, wenn validationserrors vorliegen.

In der Antwortform aogan, statt explizit durch validationsregeln zu iterieren, rufen Sie einfach 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; } }