Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / validation.cs / 1305600 / validation.cs
//---------------------------------------------------------------------------- // //// Copyright (C) 2005 by Microsoft Corporation. All rights reserved. // // // // Description: // Validation-related methods and DependencyProperties // // See specs at http://avalon/connecteddata/Specs/Validation.mht // // History: // 02/03/2005 mharper: created. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Windows; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Threading; using MS.Internal.Controls; using MS.Internal.Data; using MS.Internal.KnownBoxes; using MS.Utility; namespace System.Windows.Controls { ////// Validation-related methods and DependencyProperties /// public static class Validation { ////// ValidationError event /// public static readonly RoutedEvent ErrorEvent = EventManager.RegisterRoutedEvent("ValidationError", RoutingStrategy.Bubble, typeof(EventHandler), typeof(Validation)); /// /// Adds a handler for the ValidationError attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddErrorHandler(DependencyObject element, EventHandlerhandler) { FrameworkElement.AddHandler(element, ErrorEvent, handler); } /// /// Removes a handler for the ValidationError attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveErrorHandler(DependencyObject element, EventHandlerhandler) { FrameworkElement.RemoveHandler(element, ErrorEvent, handler); } /// /// The key needed to set the publicly read-only ValidationErrors property. /// internal static readonly DependencyPropertyKey ErrorsPropertyKey = DependencyProperty.RegisterAttachedReadOnly("Errors", typeof(ReadOnlyObservableCollection), typeof(Validation), new FrameworkPropertyMetadata( ValidationErrorCollection.Empty, FrameworkPropertyMetadataOptions.NotDataBindable)); /// /// ValidationErrors DependencyProperty. /// holds the list of all active validation errors of any data binding targeting the hosting element. /// ////// The application cannot modify the content of this collection. /// public static readonly DependencyProperty ErrorsProperty = ErrorsPropertyKey.DependencyProperty; ///Static accessor for Validation.Errors property ////// The application cannot modify the content of this collection. /// ///DependencyObject element cannot be null public static ReadOnlyObservableCollectionGetErrors(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return (ReadOnlyObservableCollection ) element.GetValue(ErrorsProperty); } /// /// holds the internally modifiable collection of validation errors. /// internal static readonly DependencyProperty ValidationErrorsInternalProperty = DependencyProperty.RegisterAttached("ErrorsInternal", typeof(ValidationErrorCollection), typeof(Validation), new FrameworkPropertyMetadata( (ValidationErrorCollection)null, new PropertyChangedCallback(OnErrorsInternalChanged))); // Update HasErrors and Invalidate the public ValidationErrors property whose GetOverride will return // the updated value of ValidationErrorsInternal, nicely wrapped into a ReadOnlyCollectionprivate static void OnErrorsInternalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ValidationErrorCollection newErrors = e.NewValue as ValidationErrorCollection; if (newErrors != null) { d.SetValue(ErrorsPropertyKey, new ReadOnlyObservableCollection (newErrors)); } else { d.ClearValue(ErrorsPropertyKey); } } internal static ValidationErrorCollection GetErrorsInternal(DependencyObject target) { return (ValidationErrorCollection) target.GetValue(Validation.ValidationErrorsInternalProperty); } /// /// The key needed set a read-only property. /// internal static readonly DependencyPropertyKey HasErrorPropertyKey = DependencyProperty.RegisterAttachedReadOnly("HasError", typeof(bool), typeof(Validation), new FrameworkPropertyMetadata( BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.NotDataBindable, OnHasErrorChanged)); // This is a workaround to notify the Control because if we try to override // metadata to have the control hook it's own property change handler // it introduces a strange ordering of static constructors when not ngened. private static void OnHasErrorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Control control = d as Control; if (control != null) { Control.OnVisualStatePropertyChanged(control, e); } } ////// HasError DependencyProperty is true if any binding on the target element /// has a validation error. /// public static readonly DependencyProperty HasErrorProperty= HasErrorPropertyKey.DependencyProperty; ///Static accessor for HasError property ///DependencyObject element cannot be null public static bool GetHasError(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return (bool) element.GetValue(HasErrorProperty); } ////// Template used to generate validation error feedback on the AdornerLayer. Default /// Template is: /// public static readonly DependencyProperty ErrorTemplateProperty = DependencyProperty.RegisterAttached("ErrorTemplate", typeof(ControlTemplate), typeof(Validation), new FrameworkPropertyMetadata( CreateDefaultErrorTemplate(), FrameworkPropertyMetadataOptions.NotDataBindable, new PropertyChangedCallback(OnErrorTemplateChanged))); //////
////// ////// Static accessor for ErrorTemplate property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static ControlTemplate GetErrorTemplate(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ErrorTemplateProperty) as ControlTemplate; } ///Static modifier for ErrorTemplate property ///DependencyObject element cannot be null public static void SetErrorTemplate(DependencyObject element, ControlTemplate value) { if (element == null) throw new ArgumentNullException("element"); // (perf) don't set if the existing value is already correct object oldValue = element.ReadLocalValue(ErrorTemplateProperty); if (!Object.Equals(oldValue, value)) element.SetValue(ErrorTemplateProperty, value); } // when ErrorTemplate changes, redraw the currently visible adorner private static void OnErrorTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (GetHasError(d)) { ShowValidationAdorner(d, false); ShowValidationAdorner(d, true); } } ////// Designates the alternative element to which validation feedback /// should be directed. /// public static readonly DependencyProperty ValidationAdornerSiteProperty = DependencyProperty.RegisterAttached("ValidationAdornerSite", typeof(DependencyObject), typeof(Validation), new FrameworkPropertyMetadata((DependencyObject)null, new PropertyChangedCallback(OnValidationAdornerSiteChanged))); ///Static accessor for ValidationAdornerSite property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static DependencyObject GetValidationAdornerSite(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ValidationAdornerSiteProperty) as DependencyObject; } ///Static modifier for ValidationAdornerSite property ///DependencyObject element cannot be null public static void SetValidationAdornerSite(DependencyObject element, DependencyObject value) { if (element == null) throw new ArgumentNullException("element"); element.SetValue(ValidationAdornerSiteProperty, value); } // when Site property changes, update the SiteFor property on the other end private static void OnValidationAdornerSiteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // ignore SubPropertyChange - we don't care about properties on the site if (e.IsASubPropertyChange) return; DependencyObject oldSite = (DependencyObject)e.OldValue; DependencyObject newSite = (DependencyObject)e.NewValue; if (oldSite != null) { oldSite.ClearValue(ValidationAdornerSiteForProperty); } if (newSite != null) { if (d != GetValidationAdornerSiteFor(newSite)) { SetValidationAdornerSiteFor(newSite, d); } } // if the adorner is currently visible, move it to the new site if (GetHasError(d)) { if (oldSite == null) { oldSite = d; } ShowValidationAdornerHelper(d, oldSite, false); ShowValidationAdorner(d, true); } } ////// Designates the element for which the current element should server /// as the public static readonly DependencyProperty ValidationAdornerSiteForProperty = DependencyProperty.RegisterAttached("ValidationAdornerSiteFor", typeof(DependencyObject), typeof(Validation), new FrameworkPropertyMetadata((DependencyObject)null, new PropertyChangedCallback(OnValidationAdornerSiteForChanged))); ///. /// Static accessor for ValidationAdornerSiteFor property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static DependencyObject GetValidationAdornerSiteFor(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ValidationAdornerSiteForProperty) as DependencyObject; } ///Static modifier for ValidationAdornerSiteFor property ///DependencyObject element cannot be null public static void SetValidationAdornerSiteFor(DependencyObject element, DependencyObject value) { if (element == null) throw new ArgumentNullException("element"); element.SetValue(ValidationAdornerSiteForProperty, value); } // when SiteFor property changes, update the Site property on the other end private static void OnValidationAdornerSiteForChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // ignore SubPropertyChange - we don't care about properties on the siteFor if (e.IsASubPropertyChange) return; DependencyObject oldSiteFor = (DependencyObject)e.OldValue; DependencyObject newSiteFor = (DependencyObject)e.NewValue; if (oldSiteFor != null) { oldSiteFor.ClearValue(ValidationAdornerSiteProperty); } if (newSiteFor != null) { if (d != GetValidationAdornerSite(newSiteFor)) { SetValidationAdornerSite(newSiteFor, d); } } } internal static void ShowValidationAdorner(DependencyObject targetElement, bool show) { // If the element has a VisualStateGroup for validation, then dont show the Adorner // because the control will handle visualizing the error via VSM states. if (!HasValidationGroup(targetElement as FrameworkElement)) { // redirect the adorner to the designated site, if any DependencyObject adornerSite = GetValidationAdornerSite(targetElement); if (adornerSite == null) { adornerSite = targetElement; } ShowValidationAdornerHelper(targetElement, adornerSite, show); } } private static bool HasValidationGroup(FrameworkElement fe) { if (fe != null) { IListgroups = VisualStateManager.GetVisualStateGroupsInternal(fe); // the Validation group could be on either the FE or it's StateGroupRoot if (HasValidationGroup(groups)) { return true; } if (fe.StateGroupsRoot != null) { groups = VisualStateManager.GetVisualStateGroupsInternal(fe.StateGroupsRoot); return HasValidationGroup(groups); } } return false; } private static bool HasValidationGroup(IList groups) { if (groups != null) { for (int groupIndex = 0; groupIndex < groups.Count; ++groupIndex) { VisualStateGroup g = groups[groupIndex]; if (g.Name == VisualStates.GroupValidation) { return true; } } } return false; } private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show) { ShowValidationAdornerHelper(targetElement, adornerSite, show, true); } private static object ShowValidationAdornerOperation(object arg) { object[] args = (object[])arg; DependencyObject targetElement = (DependencyObject)args[0]; DependencyObject adornerSite = (DependencyObject)args[1]; bool show = (bool)args[2]; ShowValidationAdornerHelper(targetElement, adornerSite, show, false); return null; } private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show, bool tryAgain) { UIElement siteUIElement = adornerSite as UIElement; if (siteUIElement != null) { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(siteUIElement); if (adornerLayer == null) { if (tryAgain) { // try again later, perhaps giving layout a chance to create the adorner layer adornerSite.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(ShowValidationAdornerOperation), new object[]{targetElement, adornerSite, show}); } return; } TemplatedAdorner validationAdorner = siteUIElement.ReadLocalValue(ValidationAdornerProperty) as TemplatedAdorner; if (show && validationAdorner == null) { // get the template from the site, or from the target element ControlTemplate validationTemplate = GetErrorTemplate(siteUIElement); if (validationTemplate == null) { validationTemplate = GetErrorTemplate(targetElement); } if (validationTemplate != null) { validationAdorner = new TemplatedAdorner(siteUIElement, validationTemplate); adornerLayer.Add(validationAdorner); siteUIElement.SetValue(ValidationAdornerProperty, validationAdorner); } } else if (!show && validationAdorner != null) { validationAdorner.ClearChild(); adornerLayer.Remove(validationAdorner); siteUIElement.ClearValue(ValidationAdornerProperty); } } } /// /// Mark this BindingExpression as invalid. If the BindingExpression has been /// explicitly marked invalid in this way, then it will remain /// invalid until ClearInvalid is called or another transfer to the source validates successfully. /// public static void MarkInvalid(BindingExpressionBase bindingExpression, ValidationError validationError) { if (bindingExpression == null) throw new ArgumentNullException("bindingExpression"); if (validationError == null) throw new ArgumentNullException("validationError"); bindingExpression.UpdateValidationError(validationError); } ////// Clears the ValidationError that was set through a call /// to MarkInvalid or a previously failed validation of that BindingExpression. /// public static void ClearInvalid(BindingExpressionBase bindingExpression) { if (bindingExpression == null) throw new ArgumentNullException("bindingExpression"); bindingExpression.UpdateValidationError(null); } // add a validation error to the given element internal static void AddValidationError(ValidationError validationError, DependencyObject targetElement, bool shouldRaiseEvent) { if (targetElement == null) return; bool wasValid; ValidationErrorCollection validationErrors = GetErrorsInternal(targetElement); if (validationErrors == null) { wasValid = true; validationErrors = new ValidationErrorCollection(); validationErrors.Add(validationError); targetElement.SetValue(Validation.ValidationErrorsInternalProperty, validationErrors); } else { wasValid = (validationErrors.Count == 0); validationErrors.Add(validationError); } if (wasValid) { targetElement.SetValue(HasErrorPropertyKey, BooleanBoxes.TrueBox); } if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Added); } if (wasValid) { ShowValidationAdorner(targetElement, true); } } // remove a validation error from the given element internal static void RemoveValidationError(ValidationError validationError, DependencyObject targetElement, bool shouldRaiseEvent) { if (targetElement == null) return; ValidationErrorCollection validationErrors = GetErrorsInternal(targetElement); if (validationErrors == null || validationErrors.Count == 0 || !validationErrors.Contains(validationError)) return; bool isValid = (validationErrors.Count == 1); // about to remove the last error if (isValid) { // instead of removing the last error, just discard the error collection. // This sends out only one property-change event, instead of two. // Any bindings to Errors[x] will appreciate the economy. targetElement.ClearValue(HasErrorPropertyKey); targetElement.ClearValue(ValidationErrorsInternalProperty); if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Removed); } ShowValidationAdorner(targetElement, false); } else { // if it's not the last error, just remove it. validationErrors.Remove(validationError); if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Removed); } } } static void OnValidationError(DependencyObject source, ValidationError validationError, ValidationErrorEventAction action) { ValidationErrorEventArgs args = new ValidationErrorEventArgs(validationError, action); if (source is ContentElement) ((ContentElement)source).RaiseEvent(args); else if (source is UIElement) ((UIElement)source).RaiseEvent(args); else if (source is UIElement3D) ((UIElement3D)source).RaiseEvent(args); } private static ControlTemplate CreateDefaultErrorTemplate() { ControlTemplate defaultTemplate = new ControlTemplate(typeof(Control)); //// FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border), "Border"); border.SetValue(Border.BorderBrushProperty, Brushes.Red); border.SetValue(Border.BorderThicknessProperty, new Thickness(1)); FrameworkElementFactory adornedElementPlaceHolder = new FrameworkElementFactory(typeof(AdornedElementPlaceholder), "Placeholder"); border.AppendChild(adornedElementPlaceHolder); defaultTemplate.VisualTree = border; defaultTemplate.Seal(); return defaultTemplate; } ///// /// Reference to the ValidationAdorner /// private static readonly DependencyProperty ValidationAdornerProperty = DependencyProperty.RegisterAttached("ValidationAdorner", typeof(TemplatedAdorner), typeof(Validation), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.NotDataBindable)); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) 2005 by Microsoft Corporation. All rights reserved. // // // // Description: // Validation-related methods and DependencyProperties // // See specs at http://avalon/connecteddata/Specs/Validation.mht // // History: // 02/03/2005 mharper: created. // //--------------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Windows; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Threading; using MS.Internal.Controls; using MS.Internal.Data; using MS.Internal.KnownBoxes; using MS.Utility; namespace System.Windows.Controls { ////// Validation-related methods and DependencyProperties /// public static class Validation { ////// ValidationError event /// public static readonly RoutedEvent ErrorEvent = EventManager.RegisterRoutedEvent("ValidationError", RoutingStrategy.Bubble, typeof(EventHandler), typeof(Validation)); /// /// Adds a handler for the ValidationError attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be added public static void AddErrorHandler(DependencyObject element, EventHandlerhandler) { FrameworkElement.AddHandler(element, ErrorEvent, handler); } /// /// Removes a handler for the ValidationError attached event /// /// UIElement or ContentElement that listens to this event /// Event Handler to be removed public static void RemoveErrorHandler(DependencyObject element, EventHandlerhandler) { FrameworkElement.RemoveHandler(element, ErrorEvent, handler); } /// /// The key needed to set the publicly read-only ValidationErrors property. /// internal static readonly DependencyPropertyKey ErrorsPropertyKey = DependencyProperty.RegisterAttachedReadOnly("Errors", typeof(ReadOnlyObservableCollection), typeof(Validation), new FrameworkPropertyMetadata( ValidationErrorCollection.Empty, FrameworkPropertyMetadataOptions.NotDataBindable)); /// /// ValidationErrors DependencyProperty. /// holds the list of all active validation errors of any data binding targeting the hosting element. /// ////// The application cannot modify the content of this collection. /// public static readonly DependencyProperty ErrorsProperty = ErrorsPropertyKey.DependencyProperty; ///Static accessor for Validation.Errors property ////// The application cannot modify the content of this collection. /// ///DependencyObject element cannot be null public static ReadOnlyObservableCollectionGetErrors(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return (ReadOnlyObservableCollection ) element.GetValue(ErrorsProperty); } /// /// holds the internally modifiable collection of validation errors. /// internal static readonly DependencyProperty ValidationErrorsInternalProperty = DependencyProperty.RegisterAttached("ErrorsInternal", typeof(ValidationErrorCollection), typeof(Validation), new FrameworkPropertyMetadata( (ValidationErrorCollection)null, new PropertyChangedCallback(OnErrorsInternalChanged))); // Update HasErrors and Invalidate the public ValidationErrors property whose GetOverride will return // the updated value of ValidationErrorsInternal, nicely wrapped into a ReadOnlyCollectionprivate static void OnErrorsInternalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ValidationErrorCollection newErrors = e.NewValue as ValidationErrorCollection; if (newErrors != null) { d.SetValue(ErrorsPropertyKey, new ReadOnlyObservableCollection (newErrors)); } else { d.ClearValue(ErrorsPropertyKey); } } internal static ValidationErrorCollection GetErrorsInternal(DependencyObject target) { return (ValidationErrorCollection) target.GetValue(Validation.ValidationErrorsInternalProperty); } /// /// The key needed set a read-only property. /// internal static readonly DependencyPropertyKey HasErrorPropertyKey = DependencyProperty.RegisterAttachedReadOnly("HasError", typeof(bool), typeof(Validation), new FrameworkPropertyMetadata( BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.NotDataBindable, OnHasErrorChanged)); // This is a workaround to notify the Control because if we try to override // metadata to have the control hook it's own property change handler // it introduces a strange ordering of static constructors when not ngened. private static void OnHasErrorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Control control = d as Control; if (control != null) { Control.OnVisualStatePropertyChanged(control, e); } } ////// HasError DependencyProperty is true if any binding on the target element /// has a validation error. /// public static readonly DependencyProperty HasErrorProperty= HasErrorPropertyKey.DependencyProperty; ///Static accessor for HasError property ///DependencyObject element cannot be null public static bool GetHasError(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return (bool) element.GetValue(HasErrorProperty); } ////// Template used to generate validation error feedback on the AdornerLayer. Default /// Template is: /// public static readonly DependencyProperty ErrorTemplateProperty = DependencyProperty.RegisterAttached("ErrorTemplate", typeof(ControlTemplate), typeof(Validation), new FrameworkPropertyMetadata( CreateDefaultErrorTemplate(), FrameworkPropertyMetadataOptions.NotDataBindable, new PropertyChangedCallback(OnErrorTemplateChanged))); //////
////// ////// Static accessor for ErrorTemplate property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static ControlTemplate GetErrorTemplate(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ErrorTemplateProperty) as ControlTemplate; } ///Static modifier for ErrorTemplate property ///DependencyObject element cannot be null public static void SetErrorTemplate(DependencyObject element, ControlTemplate value) { if (element == null) throw new ArgumentNullException("element"); // (perf) don't set if the existing value is already correct object oldValue = element.ReadLocalValue(ErrorTemplateProperty); if (!Object.Equals(oldValue, value)) element.SetValue(ErrorTemplateProperty, value); } // when ErrorTemplate changes, redraw the currently visible adorner private static void OnErrorTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (GetHasError(d)) { ShowValidationAdorner(d, false); ShowValidationAdorner(d, true); } } ////// Designates the alternative element to which validation feedback /// should be directed. /// public static readonly DependencyProperty ValidationAdornerSiteProperty = DependencyProperty.RegisterAttached("ValidationAdornerSite", typeof(DependencyObject), typeof(Validation), new FrameworkPropertyMetadata((DependencyObject)null, new PropertyChangedCallback(OnValidationAdornerSiteChanged))); ///Static accessor for ValidationAdornerSite property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static DependencyObject GetValidationAdornerSite(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ValidationAdornerSiteProperty) as DependencyObject; } ///Static modifier for ValidationAdornerSite property ///DependencyObject element cannot be null public static void SetValidationAdornerSite(DependencyObject element, DependencyObject value) { if (element == null) throw new ArgumentNullException("element"); element.SetValue(ValidationAdornerSiteProperty, value); } // when Site property changes, update the SiteFor property on the other end private static void OnValidationAdornerSiteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // ignore SubPropertyChange - we don't care about properties on the site if (e.IsASubPropertyChange) return; DependencyObject oldSite = (DependencyObject)e.OldValue; DependencyObject newSite = (DependencyObject)e.NewValue; if (oldSite != null) { oldSite.ClearValue(ValidationAdornerSiteForProperty); } if (newSite != null) { if (d != GetValidationAdornerSiteFor(newSite)) { SetValidationAdornerSiteFor(newSite, d); } } // if the adorner is currently visible, move it to the new site if (GetHasError(d)) { if (oldSite == null) { oldSite = d; } ShowValidationAdornerHelper(d, oldSite, false); ShowValidationAdorner(d, true); } } ////// Designates the element for which the current element should server /// as the public static readonly DependencyProperty ValidationAdornerSiteForProperty = DependencyProperty.RegisterAttached("ValidationAdornerSiteFor", typeof(DependencyObject), typeof(Validation), new FrameworkPropertyMetadata((DependencyObject)null, new PropertyChangedCallback(OnValidationAdornerSiteForChanged))); ///. /// Static accessor for ValidationAdornerSiteFor property ///DependencyObject element cannot be null [AttachedPropertyBrowsableForType(typeof(DependencyObject))] public static DependencyObject GetValidationAdornerSiteFor(DependencyObject element) { if (element == null) throw new ArgumentNullException("element"); return element.GetValue(ValidationAdornerSiteForProperty) as DependencyObject; } ///Static modifier for ValidationAdornerSiteFor property ///DependencyObject element cannot be null public static void SetValidationAdornerSiteFor(DependencyObject element, DependencyObject value) { if (element == null) throw new ArgumentNullException("element"); element.SetValue(ValidationAdornerSiteForProperty, value); } // when SiteFor property changes, update the Site property on the other end private static void OnValidationAdornerSiteForChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // ignore SubPropertyChange - we don't care about properties on the siteFor if (e.IsASubPropertyChange) return; DependencyObject oldSiteFor = (DependencyObject)e.OldValue; DependencyObject newSiteFor = (DependencyObject)e.NewValue; if (oldSiteFor != null) { oldSiteFor.ClearValue(ValidationAdornerSiteProperty); } if (newSiteFor != null) { if (d != GetValidationAdornerSite(newSiteFor)) { SetValidationAdornerSite(newSiteFor, d); } } } internal static void ShowValidationAdorner(DependencyObject targetElement, bool show) { // If the element has a VisualStateGroup for validation, then dont show the Adorner // because the control will handle visualizing the error via VSM states. if (!HasValidationGroup(targetElement as FrameworkElement)) { // redirect the adorner to the designated site, if any DependencyObject adornerSite = GetValidationAdornerSite(targetElement); if (adornerSite == null) { adornerSite = targetElement; } ShowValidationAdornerHelper(targetElement, adornerSite, show); } } private static bool HasValidationGroup(FrameworkElement fe) { if (fe != null) { IListgroups = VisualStateManager.GetVisualStateGroupsInternal(fe); // the Validation group could be on either the FE or it's StateGroupRoot if (HasValidationGroup(groups)) { return true; } if (fe.StateGroupsRoot != null) { groups = VisualStateManager.GetVisualStateGroupsInternal(fe.StateGroupsRoot); return HasValidationGroup(groups); } } return false; } private static bool HasValidationGroup(IList groups) { if (groups != null) { for (int groupIndex = 0; groupIndex < groups.Count; ++groupIndex) { VisualStateGroup g = groups[groupIndex]; if (g.Name == VisualStates.GroupValidation) { return true; } } } return false; } private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show) { ShowValidationAdornerHelper(targetElement, adornerSite, show, true); } private static object ShowValidationAdornerOperation(object arg) { object[] args = (object[])arg; DependencyObject targetElement = (DependencyObject)args[0]; DependencyObject adornerSite = (DependencyObject)args[1]; bool show = (bool)args[2]; ShowValidationAdornerHelper(targetElement, adornerSite, show, false); return null; } private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show, bool tryAgain) { UIElement siteUIElement = adornerSite as UIElement; if (siteUIElement != null) { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(siteUIElement); if (adornerLayer == null) { if (tryAgain) { // try again later, perhaps giving layout a chance to create the adorner layer adornerSite.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(ShowValidationAdornerOperation), new object[]{targetElement, adornerSite, show}); } return; } TemplatedAdorner validationAdorner = siteUIElement.ReadLocalValue(ValidationAdornerProperty) as TemplatedAdorner; if (show && validationAdorner == null) { // get the template from the site, or from the target element ControlTemplate validationTemplate = GetErrorTemplate(siteUIElement); if (validationTemplate == null) { validationTemplate = GetErrorTemplate(targetElement); } if (validationTemplate != null) { validationAdorner = new TemplatedAdorner(siteUIElement, validationTemplate); adornerLayer.Add(validationAdorner); siteUIElement.SetValue(ValidationAdornerProperty, validationAdorner); } } else if (!show && validationAdorner != null) { validationAdorner.ClearChild(); adornerLayer.Remove(validationAdorner); siteUIElement.ClearValue(ValidationAdornerProperty); } } } /// /// Mark this BindingExpression as invalid. If the BindingExpression has been /// explicitly marked invalid in this way, then it will remain /// invalid until ClearInvalid is called or another transfer to the source validates successfully. /// public static void MarkInvalid(BindingExpressionBase bindingExpression, ValidationError validationError) { if (bindingExpression == null) throw new ArgumentNullException("bindingExpression"); if (validationError == null) throw new ArgumentNullException("validationError"); bindingExpression.UpdateValidationError(validationError); } ////// Clears the ValidationError that was set through a call /// to MarkInvalid or a previously failed validation of that BindingExpression. /// public static void ClearInvalid(BindingExpressionBase bindingExpression) { if (bindingExpression == null) throw new ArgumentNullException("bindingExpression"); bindingExpression.UpdateValidationError(null); } // add a validation error to the given element internal static void AddValidationError(ValidationError validationError, DependencyObject targetElement, bool shouldRaiseEvent) { if (targetElement == null) return; bool wasValid; ValidationErrorCollection validationErrors = GetErrorsInternal(targetElement); if (validationErrors == null) { wasValid = true; validationErrors = new ValidationErrorCollection(); validationErrors.Add(validationError); targetElement.SetValue(Validation.ValidationErrorsInternalProperty, validationErrors); } else { wasValid = (validationErrors.Count == 0); validationErrors.Add(validationError); } if (wasValid) { targetElement.SetValue(HasErrorPropertyKey, BooleanBoxes.TrueBox); } if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Added); } if (wasValid) { ShowValidationAdorner(targetElement, true); } } // remove a validation error from the given element internal static void RemoveValidationError(ValidationError validationError, DependencyObject targetElement, bool shouldRaiseEvent) { if (targetElement == null) return; ValidationErrorCollection validationErrors = GetErrorsInternal(targetElement); if (validationErrors == null || validationErrors.Count == 0 || !validationErrors.Contains(validationError)) return; bool isValid = (validationErrors.Count == 1); // about to remove the last error if (isValid) { // instead of removing the last error, just discard the error collection. // This sends out only one property-change event, instead of two. // Any bindings to Errors[x] will appreciate the economy. targetElement.ClearValue(HasErrorPropertyKey); targetElement.ClearValue(ValidationErrorsInternalProperty); if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Removed); } ShowValidationAdorner(targetElement, false); } else { // if it's not the last error, just remove it. validationErrors.Remove(validationError); if (shouldRaiseEvent) { OnValidationError(targetElement, validationError, ValidationErrorEventAction.Removed); } } } static void OnValidationError(DependencyObject source, ValidationError validationError, ValidationErrorEventAction action) { ValidationErrorEventArgs args = new ValidationErrorEventArgs(validationError, action); if (source is ContentElement) ((ContentElement)source).RaiseEvent(args); else if (source is UIElement) ((UIElement)source).RaiseEvent(args); else if (source is UIElement3D) ((UIElement3D)source).RaiseEvent(args); } private static ControlTemplate CreateDefaultErrorTemplate() { ControlTemplate defaultTemplate = new ControlTemplate(typeof(Control)); //// FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border), "Border"); border.SetValue(Border.BorderBrushProperty, Brushes.Red); border.SetValue(Border.BorderThicknessProperty, new Thickness(1)); FrameworkElementFactory adornedElementPlaceHolder = new FrameworkElementFactory(typeof(AdornedElementPlaceholder), "Placeholder"); border.AppendChild(adornedElementPlaceHolder); defaultTemplate.VisualTree = border; defaultTemplate.Seal(); return defaultTemplate; } ///// /// Reference to the ValidationAdorner /// private static readonly DependencyProperty ValidationAdornerProperty = DependencyProperty.RegisterAttached("ValidationAdorner", typeof(TemplatedAdorner), typeof(Validation), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.NotDataBindable)); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SecurityKeyIdentifierClause.cs
- DynamicPropertyHolder.cs
- Int32Converter.cs
- PropertyGridEditorPart.cs
- DataBinding.cs
- TreeNodeConverter.cs
- TextRangeAdaptor.cs
- DataGridItemCollection.cs
- ChildTable.cs
- LayoutEditorPart.cs
- WebPartActionVerb.cs
- ActivityDesignerResources.cs
- NavigationFailedEventArgs.cs
- DateTimeOffset.cs
- XmlAttributeOverrides.cs
- RTLAwareMessageBox.cs
- Random.cs
- StringAnimationBase.cs
- GeometryHitTestResult.cs
- XmlBoundElement.cs
- GridEntryCollection.cs
- ListViewCommandEventArgs.cs
- hresults.cs
- TypeProvider.cs
- StringPropertyBuilder.cs
- shaperfactory.cs
- TransactionChannel.cs
- CallbackValidatorAttribute.cs
- Tile.cs
- StagingAreaInputItem.cs
- XmlDictionaryReaderQuotas.cs
- DataGridViewLinkCell.cs
- SkinIDTypeConverter.cs
- ValueType.cs
- Crypto.cs
- BinaryObjectWriter.cs
- HitTestWithGeometryDrawingContextWalker.cs
- UnsafeNativeMethods.cs
- RelationshipDetailsRow.cs
- TransformCryptoHandle.cs
- DateTimeValueSerializer.cs
- BinaryVersion.cs
- CollectionEditor.cs
- BaseProcessor.cs
- XmlAttributes.cs
- SocketPermission.cs
- KeyValuePairs.cs
- PreviousTrackingServiceAttribute.cs
- Site.cs
- SignatureResourcePool.cs
- ValidationRuleCollection.cs
- ReadOnlyCollection.cs
- Funcletizer.cs
- Int64KeyFrameCollection.cs
- DocumentReferenceCollection.cs
- IPGlobalProperties.cs
- MetaModel.cs
- FaultImportOptions.cs
- GeneralTransform3D.cs
- _NetRes.cs
- PanelDesigner.cs
- listviewsubitemcollectioneditor.cs
- FileClassifier.cs
- _NestedMultipleAsyncResult.cs
- StringUtil.cs
- CustomGrammar.cs
- OutputCacheProfile.cs
- RawAppCommandInputReport.cs
- ItemCollection.cs
- XPathAxisIterator.cs
- NameObjectCollectionBase.cs
- ExceptionHandler.cs
- WSDualHttpBindingElement.cs
- XmlResolver.cs
- TableCellCollection.cs
- NativeMethods.cs
- UIElement.cs
- SizeFConverter.cs
- PrintPageEvent.cs
- DataExchangeServiceBinder.cs
- FileEnumerator.cs
- ControlLocalizer.cs
- WindowsListViewItem.cs
- CqlErrorHelper.cs
- HandoffBehavior.cs
- XmlAttributeOverrides.cs
- SiteMapNodeItemEventArgs.cs
- ListViewInsertionMark.cs
- SerTrace.cs
- ValidationSummary.cs
- XamlInterfaces.cs
- HtmlEmptyTagControlBuilder.cs
- TraceSection.cs
- WhitespaceSignificantCollectionAttribute.cs
- LabelLiteral.cs
- PointCollectionConverter.cs
- FixedTextSelectionProcessor.cs
- MapPathBasedVirtualPathProvider.cs
- UnSafeCharBuffer.cs
- PerspectiveCamera.cs