水印控件
用裝飾器實現,裝飾器最大的好處就是不影響控件原本的表現的基礎之上增加一些顯示的效果,而且利于擴展。
通過擴展控件也能實現,但是部分控件是密封的,比如PasswordBox,而且還需要修改樣式是比較麻煩費力;
效果
?
?
WatermarkAdorner:定義了附加屬性、在Text的附加屬性的OnTextChanged中給對應的控件的加載事件添加了Adorner(利用反射消除控件類型及對應的控件裝飾器的判斷)
/// <summary>/// 水印裝飾器 /// </summary>public class WatermarkAdorner : Adorner{public WatermarkAdorner(UIElement adornedElement): base(adornedElement){IsHitTestVisible = false; //不可命中 InvalidateVisual();}//強制布局發生改變,根據當前信息實時繪制protected void Adorner_RoutedEvent(object sender, RoutedEventArgs e){InvalidateVisual();}#region 附加屬性public static Thickness GetMargin(DependencyObject obj){return (Thickness)obj.GetValue(MarginProperty);}public static void SetMargin(DependencyObject obj, Thickness value){obj.SetValue(MarginProperty, value);}public new readonly static DependencyProperty MarginProperty =DependencyProperty.RegisterAttached("Margin", typeof(Thickness), typeof(WatermarkAdorner), new PropertyMetadata(new Thickness(0)));public static string GetText(DependencyObject obj){return (string)obj.GetValue(TextProperty);}public static void SetText(DependencyObject obj, string value){obj.SetValue(TextProperty, value);}/// <summary>/// 文本屬性/// </summary>public static readonly DependencyProperty TextProperty =DependencyProperty.RegisterAttached("Text", typeof(string), typeof(WatermarkAdorner), new PropertyMetadata(string.Empty, OnTextChanged));private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var element = d as FrameworkElement;if (element != null){WatermarkAdorner adorner = new WatermarkAdorner(element);WatermarkAdorner watermarkAdorner = null;Type type = adorner.GetType();Assembly assembly = type.Assembly;watermarkAdorner = (WatermarkAdorner)assembly.CreateInstance(type.Namespace + "." + element.GetType().Name + "WatermarkAdorner", false, BindingFlags.CreateInstance, null, new object[] { element }, CultureInfo.CurrentCulture, null);element.Loaded += (sender, arg) =>{if (watermarkAdorner != null){AdornerLayer.GetAdornerLayer(element).Add(watermarkAdorner);}};}}public static Brush GetForeground(DependencyObject obj){return (Brush)obj.GetValue(ForegroundProperty);}public static void SetForeground(DependencyObject obj, Brush value){obj.SetValue(ForegroundProperty, value);}/// <summary>/// 前景色/// </summary>public static readonly DependencyProperty ForegroundProperty =DependencyProperty.RegisterAttached("Foreground", typeof(Brush), typeof(WatermarkAdorner), new UIPropertyMetadata(Brushes.Gray));public static Brush GetBackground(DependencyObject obj){return (Brush)obj.GetValue(BackgroundProperty);}public static void SetBackground(DependencyObject obj, Brush value){obj.SetValue(BackgroundProperty, value);}/// <summary>/// 背景色/// </summary>public static readonly DependencyProperty BackgroundProperty =DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(WatermarkAdorner), new UIPropertyMetadata(Brushes.Transparent));public static FontStyle GetFontStyle(DependencyObject obj){return (FontStyle)obj.GetValue(FontStyleProperty);}public static void SetFontStyle(DependencyObject obj, FontStyle value){obj.SetValue(FontStyleProperty, value);}/// <summary>/// 字體風格/// </summary>public static readonly DependencyProperty FontStyleProperty =DependencyProperty.RegisterAttached("FontStyle", typeof(FontStyle), typeof(WatermarkAdorner), new UIPropertyMetadata(FontStyles.Italic));#endregion} }?
TextBoxWatermarkAdorner:構造函數為控件的對應事件訂閱刷新水印事件、OnRender方法判斷是否滿足添加水印的條件以及繪制水印
?
?
PasswordBoxWatermarkAdorner:構造函數為控件的對應事件訂閱刷新水印事件、OnRender方法判斷是否滿足添加水印的條件以及繪制水印
?
public class PasswordBoxWatermarkAdorner : WatermarkAdorner{private readonly PasswordBox _adornedPasswordBox;public PasswordBoxWatermarkAdorner(UIElement adornedElement): base(adornedElement){var passwordBox = adornedElement as PasswordBox;if (passwordBox != null){_adornedPasswordBox = passwordBox;_adornedPasswordBox.LostFocus += Adorner_RoutedEvent;_adornedPasswordBox.GotFocus += Adorner_RoutedEvent;_adornedPasswordBox.PasswordChanged += Adorner_RoutedEvent;}InvalidateVisual();}protected override void OnRender(DrawingContext drawingContext){if (_adornedPasswordBox != null && (_adornedPasswordBox.IsFocused || !string.IsNullOrEmpty(_adornedPasswordBox.Password)))return;FormattedText formatted = new FormattedText(GetText(_adornedPasswordBox), CultureInfo.CurrentCulture,GetFlowDirection(_adornedPasswordBox), _adornedPasswordBox.FontFamily.GetTypefaces().FirstOrDefault(),_adornedPasswordBox.FontSize, GetForeground(_adornedPasswordBox));formatted.SetFontStyle(GetFontStyle(_adornedPasswordBox));drawingContext.DrawText(formatted,new Point(GetMargin(_adornedPasswordBox).Left, GetMargin(_adornedPasswordBox).Top));}}?
界面使用
?
2016/07/05
發現一處Bug:
AdornerLayer.GetAdornerLayer(element)可能存在返回值為空的狀況,那么程序會直接崩潰,不夠友好,這里是比較粗心大意的一個寫代碼陋習,在使用引用對象的時候沒有檢查值是否存在。1 public class WatermarkAdorner : Adorner 2 { 3 public WatermarkAdorner(UIElement adornedElement) 4 : base(adornedElement) 5 { 6 IsHitTestVisible = false; //不可命中 7 InvalidateVisual(); 8 } 9 10 //強制布局發生改變,根據當前信息實時繪制 11 protected void Adorner_RoutedEvent(object sender, RoutedEventArgs e) 12 { 13 InvalidateVisual(); 14 } 15 16 #region 附加屬性 17 18 public static Thickness GetMargin(DependencyObject obj) 19 { 20 return (Thickness)obj.GetValue(MarginProperty); 21 } 22 23 public static void SetMargin(DependencyObject obj, Thickness value) 24 { 25 obj.SetValue(MarginProperty, value); 26 } 27 28 public new readonly static DependencyProperty MarginProperty = 29 DependencyProperty.RegisterAttached("Margin", typeof(Thickness), typeof(WatermarkAdorner), new PropertyMetadata(new Thickness(0))); 30 31 public static string GetText(DependencyObject obj) 32 { 33 return (string)obj.GetValue(TextProperty); 34 } 35 36 public static void SetText(DependencyObject obj, string value) 37 { 38 obj.SetValue(TextProperty, value); 39 } 40 41 /// <summary> 42 /// 文本屬性 43 /// </summary> 44 public static readonly DependencyProperty TextProperty = 45 DependencyProperty.RegisterAttached("Text", typeof(string), typeof(WatermarkAdorner), new PropertyMetadata(string.Empty, OnTextChanged)); 46 47 private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 48 { 49 var element = d as FrameworkElement; 50 if (element != null) 51 { 52 WatermarkAdorner adorner = new WatermarkAdorner(element); 53 WatermarkAdorner watermarkAdorner = null; 54 Type type = adorner.GetType(); 55 Assembly assembly = type.Assembly; 56 watermarkAdorner = (WatermarkAdorner)assembly.CreateInstance(type.Namespace + "." + element.GetType().Name + "WatermarkAdorner", false, BindingFlags.CreateInstance, null, new object[] { element }, CultureInfo.CurrentCulture, null); 57 58 element.Loaded += (sender, arg) => 59 { 60 if (watermarkAdorner != null) 61 { 62 var adornerLayer = GetAdornerLayer(element); 63 if (adornerLayer != null) 64 { 65 adornerLayer.Add(watermarkAdorner); 66 } 67 } 68 }; 69 } 70 } 71 72 private static AdornerLayer GetAdornerLayer(FrameworkElement element) 73 { 74 if (element == null) return null; 75 76 AdornerLayer layer = AdornerLayer.GetAdornerLayer(element); 77 var parent = element.Parent as FrameworkElement; 78 while (layer == null) 79 { 80 if (parent != null) 81 { 82 layer = AdornerLayer.GetAdornerLayer(parent); 83 parent = parent.Parent as FrameworkElement; 84 } 85 else break; 86 } 87 88 return layer; 89 } 90 91 public static Brush GetForeground(DependencyObject obj) 92 { 93 return (Brush)obj.GetValue(ForegroundProperty); 94 } 95 96 public static void SetForeground(DependencyObject obj, Brush value) 97 { 98 obj.SetValue(ForegroundProperty, value); 99 } 100 101 /// <summary> 102 /// 前景色 103 /// </summary> 104 public static readonly DependencyProperty ForegroundProperty = 105 DependencyProperty.RegisterAttached("Foreground", typeof(Brush), typeof(WatermarkAdorner), new UIPropertyMetadata(Brushes.Gray)); 106 107 public static Brush GetBackground(DependencyObject obj) 108 { 109 return (Brush)obj.GetValue(BackgroundProperty); 110 } 111 112 public static void SetBackground(DependencyObject obj, Brush value) 113 { 114 obj.SetValue(BackgroundProperty, value); 115 } 116 117 /// <summary> 118 /// 背景色 119 /// </summary> 120 public static readonly DependencyProperty BackgroundProperty = 121 DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(WatermarkAdorner), new UIPropertyMetadata(Brushes.Transparent)); 122 123 124 public static FontStyle GetFontStyle(DependencyObject obj) 125 { 126 return (FontStyle)obj.GetValue(FontStyleProperty); 127 } 128 129 public static void SetFontStyle(DependencyObject obj, FontStyle value) 130 { 131 obj.SetValue(FontStyleProperty, value); 132 } 133 134 /// <summary> 135 /// 字體風格 136 /// </summary> 137 public static readonly DependencyProperty FontStyleProperty = 138 DependencyProperty.RegisterAttached("FontStyle", typeof(FontStyle), typeof(WatermarkAdorner), new UIPropertyMetadata(FontStyles.Italic)); 139 140 #endregion 141 }
2016.8.16添加,用于WatermarkAdorner在無法獲取AdornerLayer的場景下獲取AdornerLayer
?轉載于:https://www.cnblogs.com/XzcBlog/p/4940303.html
總結
- 上一篇: 浅谈软件性能测试中关键指标的监控与分析(
- 下一篇: xss漏洞挖掘小结