在WPF中,您可以使用ExceptionValidationRule
或在数据绑定期间根据数据层中抛出的错误设置验证DataErrorValidationRule
.
假设你有一堆这样设置的控件,你有一个Save按钮.当用户单击"保存"按钮时,您需要确保在继续保存之前没有验证错误.如果存在验证错误,您希望对它们大声疾呼.
在WPF中,如何确定是否有任何数据绑定控件设置了验证错误?
这篇文章非常有帮助.感谢所有贡献者.这是一个你会喜欢或讨厌的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() .All(IsValid); }
以下代码(来自Chris Sell和Ian Griffiths的Programming 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 { .... } }
使用ListBox时,发布的代码对我不起作用.我重写了它,现在它的工作原理:
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; }
有同样的问题,并尝试提供的解决方案.H-Man2和skiba_k解决方案的组合对我来说几乎没问题,但有一个例外:My Window有一个TabControl.并且仅针对当前可见的TabItem评估验证规则.所以我用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; }
除了Dean的出色LINQ实现之外,我还很乐意将代码包装到DependencyObjects的扩展中:
public static bool IsValid(this DependencyObject instance) { // Validate recursivly return !Validation.GetHasError(instance) && LogicalTreeHelper.GetChildren(instance).OfType().All(child => child.IsValid()); }
考虑到重复使用,这非常好.