在做表单的,需要对User提交数据做验证,wpf与silverlight 都提供自带的验证机制,但是只是验证,并不能在提交时提供详细的信息,此时可使用 依赖属性将错误信息整合进自定义错误集合中,即可在提交时获取相应错误信息方便后续业务处理。
Silverlifgt版本:
public class ValidationScope
{
public FrameworkElement ScopeElement { get; private set; }
private readonly ObservableCollection<ValidationError> _errors = new ObservableCollection<ValidationError>();
public ObservableCollection<ValidationError> Errors
{
get { return _errors; }
}
public bool IsValid()
{
return _errors.Count == 0;
}
public static string GetValidateBoundProperty(DependencyObject obj)
{
return (string)obj.GetValue(ValidateBoundPropertyProperty);
}
public static void SetValidateBoundProperty(DependencyObject obj, string value)
{
obj.SetValue(ValidateBoundPropertyProperty, value);
}
public static readonly DependencyProperty ValidateBoundPropertyProperty =
DependencyProperty.RegisterAttached("ValidateBoundProperty", typeof(string), typeof(ValidationScope), new PropertyMetadata(null));
public static ValidationScope GetValidationScope(DependencyObject obj)
{
return (ValidationScope)obj.GetValue(ValidationScopeProperty);
}
public static void SetValidationScope(DependencyObject obj, ValidationScope value)
{
obj.SetValue(ValidationScopeProperty, value);
}
public static readonly DependencyProperty ValidationScopeProperty =
DependencyProperty.RegisterAttached("ValidationScope", typeof(ValidationScope), typeof(ValidationScope), new PropertyMetadata(null, ValidationScopeChanged));
private static void ValidationScopeChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ValidationScope oldScope = args.OldValue as ValidationScope;
if (oldScope != null)
{
oldScope.ScopeElement.BindingValidationError -= oldScope.ScopeElement_BindingValidationError;
oldScope.ScopeElement = null;
}
FrameworkElement scopeElement = source as FrameworkElement;
if (scopeElement == null)
{
throw new ArgumentException(string.Format(
"'{0}' is not a valid type.ValidationScope attached property can only be specified on types inheriting from FrameworkElement.",
source));
}
ValidationScope newScope = (ValidationScope)args.NewValue;
newScope.ScopeElement = scopeElement;
newScope.ScopeElement.BindingValidationError += newScope.ScopeElement_BindingValidationError;
}
private void ScopeElement_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Removed)
{
Errors.Remove(e.Error);
}
else if (e.Action == ValidationErrorEventAction.Added)
{
Errors.Add(e.Error);
}
}
public void ValidateScope()
{
ForEachElement(ScopeElement, delegate(DependencyObject obj)
{
string propertyName = GetValidateBoundProperty(obj);
if (!string.IsNullOrEmpty(propertyName))
{
FrameworkElement element = (FrameworkElement)obj;
var field = element.GetType().GetFields(BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public)
.Where(p => p.FieldType == typeof(DependencyProperty) && p.Name == (propertyName + "Property"))
.FirstOrDefault();
if (field == null)
{
throw new ArgumentException(string.Format(
"Dependency property '{0}' could not be found on type '{1}'; ValidationScope.ValidateBoundProperty",
propertyName, element.GetType()));
}
var be = element.GetBindingExpression((DependencyProperty)field.GetValue(null));
be.UpdateSource();
}
});
}
private static void ForEachElement(DependencyObject root, Action<DependencyObject> action)
{
int childCount = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < childCount; i++)
{
var obj = VisualTreeHelper.GetChild(root, i);
action(obj);
ForEachElement(obj, action);
}
}
}
WPF版:
public class ValidationScope
{
public FrameworkElement ScopeElement { get; private set; }
private readonly ObservableCollection<ValidationError> _errors = new ObservableCollection<ValidationError>();
public ObservableCollection<ValidationError> Errors
{
get { return _errors; }
}
public bool IsValid()
{
return _errors.Count == 0;
}
public static string GetValidateBoundProperty(DependencyObject obj)
{
return (string)obj.GetValue(ValidateBoundPropertyProperty);
}
public static void SetValidateBoundProperty(DependencyObject obj, string value)
{
obj.SetValue(ValidateBoundPropertyProperty, value);
}
public static readonly DependencyProperty ValidateBoundPropertyProperty =
DependencyProperty.RegisterAttached("ValidateBoundProperty", typeof(string), typeof(ValidationScope), new PropertyMetadata(null));
public static ValidationScope GetValidationScope(DependencyObject obj)
{
return (ValidationScope)obj.GetValue(ValidationScopeProperty);
}
public static void SetValidationScope(DependencyObject obj, ValidationScope value)
{
obj.SetValue(ValidationScopeProperty, value);
}
public static readonly DependencyProperty ValidationScopeProperty =
DependencyProperty.RegisterAttached("ValidationScope", typeof(ValidationScope), typeof(ValidationScope), new PropertyMetadata(null, ValidationScopeChanged));
private static void ValidationScopeChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
ValidationScope oldScope = args.OldValue as ValidationScope;
if (oldScope != null)
{
oldScope.ScopeElement.RemoveHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(oldScope.ScopeElement_BindingValidationError));
oldScope.ScopeElement = null;
}
FrameworkElement scopeElement = source as FrameworkElement;
if (scopeElement == null)
{
throw new ArgumentException(string.Format(
"'{0}' is not a valid type.ValidationScope attached property can only be specified on types inheriting from FrameworkElement.",
source));
}
ValidationScope newScope = (ValidationScope)args.NewValue;
newScope.ScopeElement = scopeElement;
newScope.ScopeElement.AddHandler(System.Windows.Controls.Validation.ErrorEvent, new RoutedEventHandler(newScope.ScopeElement_BindingValidationError), true);
}
public void ScopeElement_BindingValidationError(object sender, RoutedEventArgs e)
{
System.Windows.Controls.ValidationErrorEventArgs args = e as System.Windows.Controls.ValidationErrorEventArgs;
if (args.Error.RuleInError is System.Windows.Controls.ValidationRule)
{
BindingExpression bindingExpression = args.Error.BindingInError as System.Windows.Data.BindingExpression;
string propertyName = bindingExpression.ParentBinding.Path.Path;
DependencyObject OriginalSource = args.OriginalSource as DependencyObject;
string errorMessage = "";
ReadOnlyObservableCollection<System.Windows.Controls.ValidationError> errors = System.Windows.Controls.Validation.GetErrors(OriginalSource);
if (errors.Count > 0)
{
StringBuilder builder = new StringBuilder();
builder.Append(propertyName).Append(":");
System.Windows.Controls.ValidationError error = errors[errors.Count - 1];
{
if (error.Exception == null || error.Exception.InnerException == null)
builder.Append(error.ErrorContent.ToString());
else
builder.Append(error.Exception.InnerException.Message);
}
errorMessage = builder.ToString();
}
StringBuilder errorID = new StringBuilder();
errorID.Append(args.Error.RuleInError.ToString());
if (args.Action == ValidationErrorEventAction.Added)
{
Errors.Add(args.Error);
}
else if (args.Action == ValidationErrorEventAction.Removed)
{
Errors.Remove(args.Error);
}
}
}
public void ValidateScope()
{
ForEachElement(ScopeElement, delegate(DependencyObject obj)
{
string propertyName = GetValidateBoundProperty(obj);
if (!string.IsNullOrEmpty(propertyName))
{
FrameworkElement element = (FrameworkElement)obj;
var field = element.GetType().GetFields(BindingFlags.Static | BindingFlags.FlattenHierarchy | BindingFlags.Public)
.Where(p => p.FieldType == typeof(DependencyProperty) && p.Name == (propertyName + "Property"))
.FirstOrDefault();
if (field == null)
{
throw new ArgumentException(string.Format(
"Dependency property '{0}' could not be found on type '{1}'; ValidationScope.ValidateBoundProperty",
propertyName, element.GetType()));
}
var be = element.GetBindingExpression((DependencyProperty)field.GetValue(null));
be.UpdateSource();
}
});
}
private static void ForEachElement(DependencyObject root, Action<DependencyObject> action)
{
int childCount = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < childCount; i++)
{
var obj = VisualTreeHelper.GetChild(root, i);
action(obj);
ForEachElement(obj, action);
}
}
}