using System; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Media.Imaging; namespace Developpez.Dotnet.Windows.Behaviors { /// /// Fournit une indication visuelle d'une erreur de validation sur un contrôle /// public static class ErrorProvider { /// /// Obtient la valeur de la propriété attachée ErrorMessage pour le contrôle /// /// Contrôle pour lequel on veut obtenir la valeur de la propriété /// Le message d'erreur associé à ce contrôle public static string GetErrorMessage(this FrameworkElement obj) { return (string)obj.GetValue(ErrorMessageProperty); } /// /// Définit la valeur de la propriété attachée ErrorMessage pour le contrôle /// /// Contrôle pour lequel on définit la valeur de la propriété /// Le message d'erreur à associer à ce contrôle public static void SetErrorMessage(this FrameworkElement obj, string value) { obj.SetValue(ErrorMessageProperty, value); } /// /// Identifiant de la propriété attachée ErrorMessage /// public static readonly DependencyProperty ErrorMessageProperty = DependencyProperty.RegisterAttached( "ErrorMessage", typeof(string), typeof(ErrorProvider), new UIPropertyMetadata( null, ErrorMessageChanged)); /// /// Obtient la valeur de la propriété attachée IconSource pour le contrôle /// /// Contrôle pour lequel on veut obtenir la valeur de la propriété /// L'icône d'erreur utilisée sur ce contrôle public static ImageSource GetIconSource(FrameworkElement obj) { return (ImageSource)obj.GetValue(IconSourceProperty); } /// /// Définit la valeur de la propriété attachée IconSource pour le contrôle /// /// Contrôle pour lequel on définit la valeur de la propriété /// L'icône d'erreur à utiliser sur ce contrôle public static void SetIconSource(FrameworkElement obj, ImageSource value) { obj.SetValue(IconSourceProperty, value); } /// /// Identifiant de la propriété attachée IconSource /// public static readonly DependencyProperty IconSourceProperty = DependencyProperty.RegisterAttached( "IconSource", typeof(ImageSource), typeof(ErrorProvider), new FrameworkPropertyMetadata(GetDefaultErrorIcon(), FrameworkPropertyMetadataOptions.Inherits)); /// /// Obtient la valeur de la propriété attachée IconHorizontalAlignment pour le contrôle /// /// Contrôle pour lequel on veut obtenir la valeur de la propriété /// L'alignement horizontal de l'icône d'erreur public static HorizontalAlignment GetIconHorizontalAlignment(FrameworkElement obj) { return (HorizontalAlignment)obj.GetValue(IconHorizontalAlignmentProperty); } /// /// Définit la valeur de la propriété attachée IconHorizontalAlignment pour le contrôle /// /// Contrôle pour lequel on définit la valeur de la propriété /// L'alignement horizontal de l'icône d'erreur public static void SetIconHorizontalAlignment(FrameworkElement obj, HorizontalAlignment value) { obj.SetValue(IconHorizontalAlignmentProperty, value); } /// /// Identifiant de la propriété attachée IconHorizontalAlignment /// public static readonly DependencyProperty IconHorizontalAlignmentProperty = DependencyProperty.RegisterAttached("IconHorizontalAlignment", typeof(HorizontalAlignment), typeof(ErrorProvider), new UIPropertyMetadata(HorizontalAlignment.Right)); /// /// Obtient la valeur de la propriété attachée IconVerticalAlignment pour le contrôle /// /// Contrôle pour lequel on veut obtenir la valeur de la propriété /// L'alignement vertical de l'icône d'erreur public static VerticalAlignment GetIconVerticalAlignment(DependencyObject obj) { return (VerticalAlignment)obj.GetValue(IconVerticalAlignmentProperty); } /// /// Définit la valeur de la propriété attachée IconVerticalAlignment pour le contrôle /// /// Contrôle pour lequel on définit la valeur de la propriété /// L'alignement vertical de l'icône d'erreur public static void SetIconVerticalAlignment(DependencyObject obj, VerticalAlignment value) { obj.SetValue(IconVerticalAlignmentProperty, value); } /// /// Identifiant de la propriété attachée IconVerticalAlignment /// public static readonly DependencyProperty IconVerticalAlignmentProperty = DependencyProperty.RegisterAttached("IconVerticalAlignment", typeof(VerticalAlignment), typeof(ErrorProvider), new UIPropertyMetadata(VerticalAlignment.Center)); private static void ErrorMessageChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var element = o as FrameworkElement; if (element == null) return; var oldValue = (string)e.OldValue; var newValue = (string)e.NewValue; if (!string.IsNullOrEmpty(oldValue) && string.IsNullOrEmpty(newValue)) { element.DoWhenLoaded(RemoveErrorAdorner); } else if (!string.IsNullOrEmpty(newValue) && string.IsNullOrEmpty(oldValue)) { element.DoWhenLoaded(AddErrorAdorner); } } private static void RemoveErrorAdorner(UIElement uiElement) { var layer = AdornerLayer.GetAdornerLayer(uiElement); if (layer == null) return; var adorner = layer.GetAdorners(uiElement).OfType().FirstOrDefault(); if (adorner != null) layer.Remove(adorner); } private static void AddErrorAdorner(UIElement uiElement) { var layer = AdornerLayer.GetAdornerLayer(uiElement); if (layer == null) return; var adorner = new ErrorAdorner(uiElement); layer.Add(adorner); } private static ImageSource GetDefaultErrorIcon() { return new BitmapImage( new Uri("pack://application:,,,/Developpez.Dotnet.Windows;component/Images/error.png")); } private class ErrorAdorner : Adorner { private readonly Border _errorBorder; public ErrorAdorner(UIElement adornedElement) : base(adornedElement) { _errorBorder = new Border(); _errorBorder.BorderThickness = new Thickness(2); _errorBorder.BorderBrush = Brushes.Red; Image img = new Image(); img.Stretch = Stretch.None; BindToAdornedElement(img, Image.SourceProperty, IconSourceProperty); BindToAdornedElement(img, ToolTipProperty, ErrorMessageProperty); BindToAdornedElement(img, HorizontalAlignmentProperty, IconHorizontalAlignmentProperty); BindToAdornedElement(img, VerticalAlignmentProperty, IconVerticalAlignmentProperty); _errorBorder.Child = img; this.AddLogicalChild(_errorBorder); this.AddVisualChild(_errorBorder); } void BindToAdornedElement(FrameworkElement target, DependencyProperty targetProperty, DependencyProperty sourceProperty) { Binding binding = new Binding { Source = AdornedElement, Path = new PropertyPath(sourceProperty) }; target.SetBinding(targetProperty, binding); } protected override Size MeasureOverride(Size constraint) { AdornedElement.Measure(constraint); return AdornedElement.RenderSize; } protected override Size ArrangeOverride(Size finalSize) { _errorBorder.Arrange(new Rect(finalSize)); return finalSize; } protected override Visual GetVisualChild(int index) { if (index == 0) return _errorBorder; throw new ArgumentOutOfRangeException("index"); } protected override int VisualChildrenCount { get { return 1; } } protected override System.Collections.IEnumerator LogicalChildren { get { yield return _errorBorder; } } } } }