WatermarkAdorner.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Documents;
  5. using System.Windows.Media;
  6. namespace CustomUI
  7. {
  8. /// <summary>
  9. /// 水印显示方式
  10. /// </summary>
  11. public enum EnumWatermarkShowMode
  12. {
  13. /// <summary>
  14. /// 当文本框为空时就显示水印,不管该文本框有没有获得焦点
  15. /// </summary>
  16. VisibleWhenIsEmpty,
  17. /// <summary>
  18. /// 当文本框失去焦点且文本框没有内容时显示水印
  19. /// </summary>
  20. VisibleWhenLostFocusAndEmpty,
  21. }
  22. /// <summary>
  23. /// TextBox文本框通用水印
  24. /// </summary>
  25. /// <remarks>add by zhidf 2017.9.3</remarks>
  26. public class WatermarkAdorner : Adorner
  27. {
  28. private TextBox adornedTextBox;
  29. private VisualCollection _visuals;
  30. private TextBlock textBlock;
  31. private EnumWatermarkShowMode showModel;
  32. #region Watermark
  33. public static string GetWatermark(DependencyObject obj)
  34. {
  35. return (string)obj.GetValue(WatermarkProperty);
  36. }
  37. public static void SetWatermark(DependencyObject obj, string value)
  38. {
  39. obj.SetValue(WatermarkProperty, value);
  40. }
  41. public static readonly DependencyProperty WatermarkProperty =
  42. DependencyProperty.RegisterAttached("Watermark", typeof(string), typeof(WatermarkAdorner)
  43. , new PropertyMetadata(string.Empty, WatermarkChangedCallBack));
  44. #endregion
  45. #region WatermarkShowMode
  46. public static EnumWatermarkShowMode GetWatermarkShowMode(DependencyObject obj)
  47. {
  48. return (EnumWatermarkShowMode)obj.GetValue(WatermarkShowModeProperty);
  49. }
  50. public static void SetWatermarkShowMode(DependencyObject obj, EnumWatermarkShowMode value)
  51. {
  52. obj.SetValue(WatermarkShowModeProperty, value);
  53. }
  54. public static readonly DependencyProperty WatermarkShowModeProperty =
  55. DependencyProperty.RegisterAttached("WatermarkShowMode", typeof(EnumWatermarkShowMode), typeof(WatermarkAdorner), new PropertyMetadata(EnumWatermarkShowMode.VisibleWhenLostFocusAndEmpty));
  56. #endregion
  57. private static void WatermarkChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
  58. {
  59. try
  60. {
  61. var element = d as FrameworkElement;
  62. if (element != null)
  63. {
  64. var adornerLayer = AdornerLayer.GetAdornerLayer(element);
  65. if (adornerLayer != null)
  66. {
  67. adornerLayer.Add(new WatermarkAdorner(element as UIElement));
  68. }
  69. else
  70. {
  71. WatermarkAdorner adorner = null;
  72. //增加Initialized事件处理是为了解决当水印放置在TabControl中时导致水印频繁的Loaded和Unload
  73. element.Initialized += (o1, e1) =>
  74. {
  75. adorner = new WatermarkAdorner(element);
  76. };
  77. //layer为null,说明还未load过(整个可视化树中没有装饰层的情况不考虑)
  78. //在控件的loaded事件内生成装饰件
  79. element.Loaded += (s1, e1) =>
  80. {
  81. var v = AdornerLayer.GetAdornerLayer(element);
  82. if(v != null && adorner != null)
  83. {
  84. v.Add(adorner);
  85. }
  86. };
  87. element.Unloaded += (s1, e1) =>
  88. {
  89. var v = AdornerLayer.GetAdornerLayer(element);
  90. if (v != null && adorner != null)
  91. {
  92. v.Remove(adorner);
  93. }
  94. };
  95. }
  96. }
  97. }
  98. catch (Exception)
  99. {
  100. }
  101. }
  102. public WatermarkAdorner(UIElement adornedElement) : base(adornedElement)
  103. {
  104. if (adornedElement is TextBox)
  105. {
  106. adornedTextBox = adornedElement as TextBox;
  107. adornedTextBox.TextChanged += (s1, e1) =>
  108. {
  109. this.SetWatermarkVisible(true);
  110. };
  111. adornedTextBox.GotFocus += (s1, e1) =>
  112. {
  113. this.SetWatermarkVisible(true);
  114. };
  115. adornedTextBox.LostFocus += (s1, e1) =>
  116. {
  117. this.SetWatermarkVisible(false);
  118. };
  119. adornedTextBox.IsVisibleChanged += (o, e) =>
  120. {
  121. if(string.IsNullOrEmpty(this.adornedTextBox.Text))
  122. {
  123. this.textBlock.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;
  124. }
  125. else
  126. {
  127. this.textBlock.Visibility = Visibility.Collapsed;
  128. }
  129. };
  130. _visuals = new VisualCollection(this);
  131. textBlock = new TextBlock()
  132. {
  133. HorizontalAlignment = adornedTextBox.HorizontalContentAlignment,
  134. VerticalAlignment = adornedTextBox.VerticalContentAlignment,
  135. Text = WatermarkAdorner.GetWatermark(adornedElement),
  136. Foreground = new SolidColorBrush(Color.FromRgb(153, 153, 153)),
  137. Margin = new Thickness(5,0,2,0),
  138. };
  139. _visuals.Add(textBlock);
  140. this.showModel = WatermarkAdorner.GetWatermarkShowMode(adornedElement);
  141. }
  142. this.IsHitTestVisible = false;
  143. }
  144. protected override int VisualChildrenCount
  145. {
  146. get
  147. {
  148. return _visuals.Count;
  149. }
  150. }
  151. protected override Visual GetVisualChild(int index)
  152. {
  153. return _visuals[index];
  154. }
  155. protected override Size MeasureOverride(Size constraint)
  156. {
  157. return base.MeasureOverride(constraint);
  158. }
  159. protected override Size ArrangeOverride(Size finalSize)
  160. {
  161. textBlock.Arrange(new Rect(finalSize));
  162. return base.ArrangeOverride(finalSize);
  163. }
  164. private void SetWatermarkVisible(bool isFocus)
  165. {
  166. switch (this.showModel)
  167. {
  168. case EnumWatermarkShowMode.VisibleWhenIsEmpty:
  169. if (string.IsNullOrEmpty(this.adornedTextBox.Text))
  170. {
  171. this.textBlock.Visibility = Visibility.Visible;
  172. if(!this.adornedTextBox.IsVisible)
  173. {
  174. this.textBlock.Visibility = Visibility.Collapsed;
  175. }
  176. }
  177. else
  178. {
  179. this.textBlock.Visibility = Visibility.Collapsed;
  180. }
  181. break;
  182. case EnumWatermarkShowMode.VisibleWhenLostFocusAndEmpty:
  183. if(!isFocus && string.IsNullOrEmpty(this.adornedTextBox.Text))
  184. {
  185. this.textBlock.Visibility = Visibility.Visible;
  186. }
  187. else
  188. {
  189. this.textBlock.Visibility = Visibility.Collapsed;
  190. }
  191. break;
  192. default:
  193. break;
  194. }
  195. }
  196. }
  197. }