andrew4582

WPF TextBox Watermark Extension

Oct 29th, 2014
296
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.45 KB | None | 0 0
  1. using System;
  2. using System.Linq;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Data;
  6. using System.Windows.Documents;
  7. using System.Windows.Media;
  8.  
  9. namespace MyApp.Extensions
  10. {
  11.     /// <summary>
  12.     /// Extension add/remove a watermark to a textbox
  13.     /// <remarks>
  14.     ///  //Add namespace to xaml - xmlns:ext="clr-namespace:MyApp.Extensions"
  15.     ///  <TextBox ext:Watermark.Text="Your Watermark Goes Here"/>
  16.     /// </remarks>
  17.     /// </summary>
  18.     public static class Watermark
  19.     {
  20.         public static readonly DependencyProperty TextProperty =
  21.             DependencyProperty.RegisterAttached("Text", typeof(string), typeof(Watermark), new PropertyMetadata(new PropertyChangedCallback(OnTextChanged)));
  22.  
  23.         public static string GetText(DependencyObject obj)
  24.         {
  25.             return (string)obj.GetValue(TextProperty);
  26.         }
  27.  
  28.         public static void SetText(DependencyObject obj, string value)
  29.         {
  30.             obj.SetValue(TextProperty, value);
  31.         }
  32.  
  33.         static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  34.         {
  35.             var control = d as TextBox;
  36.             if (control == null)
  37.                 return;
  38.            
  39.             if (e.OldValue != null)
  40.             {
  41.                 control.Loaded -= control_Loaded;
  42.                 control.GotFocus -= control_GotFocus;
  43.                 control.LostFocus -= control_LostFocus;
  44.                 control.TextChanged -= control_TextChanged;
  45.             }
  46.  
  47.             if (e.NewValue != null)
  48.             {
  49.                 control.Loaded += control_Loaded;
  50.                 control.GotFocus += control_GotFocus;
  51.                 control.LostFocus += control_LostFocus;
  52.                 control.TextChanged += control_TextChanged;
  53.             }
  54.         }
  55.  
  56.         static void control_Loaded(object sender, RoutedEventArgs e)
  57.         {
  58.             var control = sender as TextBox;
  59.             if (control == null)
  60.                 return;
  61.             if (string.IsNullOrWhiteSpace(control.Text))
  62.                 AddWatermark(control);
  63.         }
  64.  
  65.         static void control_GotFocus(object sender, RoutedEventArgs e)
  66.         {
  67.             var control = sender as TextBox;
  68.             if (control == null)
  69.                 return;
  70.             RemoveWatermark(control);
  71.         }
  72.  
  73.         static void control_LostFocus(object sender, RoutedEventArgs e)
  74.         {
  75.             var control = sender as TextBox;
  76.             if (control == null)
  77.                 return;
  78.  
  79.             if (string.IsNullOrWhiteSpace(control.Text))
  80.                 AddWatermark(control);
  81.         }
  82.  
  83.         static void control_TextChanged(object sender, TextChangedEventArgs e)
  84.         {
  85.             var control = sender as TextBox;
  86.             if (control == null)
  87.                 return;
  88.  
  89.             if (string.IsNullOrWhiteSpace(control.Text) && !control.IsKeyboardFocusWithin)
  90.                 AddWatermark(control);
  91.             else
  92.                 RemoveWatermark(control);
  93.         }
  94.  
  95.         /// <summary>
  96.         /// Show the watermark on the specified control
  97.         /// </summary>
  98.         /// <param name="control">Control to show the watermark on</param>
  99.         static void AddWatermark(Control control)
  100.         {
  101.             AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
  102.  
  103.             // layer could be null if control is no longer in the visual tree
  104.             if (layer != null)
  105.             {
  106.                 //check to see if control already has an adorner
  107.                 Adorner[] adorners = layer.GetAdorners(control);
  108.                 if (adorners != null)
  109.                 {
  110.                     foreach (Adorner adorner in adorners)
  111.                     {
  112.                         if (adorner is WatermarkAdorner)
  113.                             return;
  114.                     }
  115.                 }
  116.                 layer.Add(new WatermarkAdorner(control, GetText(control)));
  117.             }
  118.         }
  119.  
  120.         /// <summary>
  121.         /// Remove the watermark from the specified element
  122.         /// </summary>
  123.         /// <param name="control">Element to remove the watermark from</param>
  124.         static void RemoveWatermark(UIElement control)
  125.         {
  126.             AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
  127.  
  128.             // layer could be null if control is no longer in the visual tree
  129.             if (layer != null)
  130.             {
  131.                 Adorner[] adorners = layer.GetAdorners(control);
  132.                 if (adorners == null)
  133.                     return;
  134.                
  135.                 foreach (Adorner adorner in adorners)
  136.                 {
  137.                     if (adorner is WatermarkAdorner)
  138.                     {
  139.                         adorner.Visibility = Visibility.Hidden;
  140.                         layer.Remove(adorner);
  141.                     }
  142.                 }
  143.             }
  144.         }
  145.     }
  146.  
  147.     /// <summary>
  148.     /// Adorner for the watermark
  149.     /// </summary>
  150.     public class WatermarkAdorner : Adorner
  151.     {
  152.         #region Private Fields
  153.  
  154.         /// <summary>
  155.         /// <see cref="ContentPresenter"/> that holds the watermark
  156.         /// </summary>
  157.         private readonly ContentPresenter contentPresenter;
  158.  
  159.         #endregion
  160.  
  161.         #region Constructor
  162.  
  163.         /// <summary>
  164.         /// Initializes a new instance of the <see cref="WatermarkAdorner"/> class
  165.         /// </summary>
  166.         /// <param name="adornedElement"><see cref="UIElement"/> to be adorned</param>
  167.         /// <param name="watermark">The watermark</param>
  168.         public WatermarkAdorner(UIElement adornedElement, object watermark) :
  169.             base(adornedElement)
  170.         {
  171.             this.IsHitTestVisible = false;
  172.  
  173.             this.contentPresenter = new ContentPresenter();
  174.             this.contentPresenter.Content = watermark;
  175.             this.contentPresenter.Opacity = 0.5;
  176.             this.contentPresenter.Margin = new Thickness(Control.Margin.Left + Control.Padding.Left, Control.Margin.Top + Control.Padding.Top, 0, 0);
  177.  
  178.             if (this.Control is ItemsControl && !(this.Control is ComboBox))
  179.             {
  180.                 this.contentPresenter.VerticalAlignment = VerticalAlignment.Center;
  181.                 this.contentPresenter.HorizontalAlignment = HorizontalAlignment.Center;
  182.             }
  183.  
  184.             // Hide the control adorner when the adorned element is hidden
  185.             Binding binding = new Binding("IsVisible");
  186.             binding.Source = adornedElement;
  187.             binding.Converter = new BooleanToVisibilityConverter();
  188.             this.SetBinding(VisibilityProperty, binding);
  189.  
  190.             this.Margin = new Thickness(Control.Padding.Left, Control.Padding.Top, Control.Padding.Right, Control.Padding.Bottom);
  191.         }
  192.  
  193.         #endregion
  194.  
  195.         #region Protected Properties
  196.  
  197.         /// <summary>
  198.         /// Gets the number of children for the <see cref="ContainerVisual"/>.
  199.         /// </summary>
  200.         protected override int VisualChildrenCount
  201.         {
  202.             get { return 1; }
  203.         }
  204.  
  205.         #endregion
  206.  
  207.         #region Private Properties
  208.  
  209.         /// <summary>
  210.         /// Gets the control that is being adorned
  211.         /// </summary>
  212.         private Control Control
  213.         {
  214.             get { return (Control)this.AdornedElement; }
  215.         }
  216.  
  217.         #endregion
  218.  
  219.         #region Protected Overrides
  220.  
  221.         /// <summary>
  222.         /// Returns a specified child <see cref="Visual"/> for the parent <see cref="ContainerVisual"/>.
  223.         /// </summary>
  224.         /// <param name="index">A 32-bit signed integer that represents the index value of the child <see cref="Visual"/>. The value of index must be between 0 and <see cref="VisualChildrenCount"/> - 1.</param>
  225.         /// <returns>The child <see cref="Visual"/>.</returns>
  226.         protected override Visual GetVisualChild(int index)
  227.         {
  228.             return this.contentPresenter;
  229.         }
  230.  
  231.         /// <summary>
  232.         /// Implements any custom measuring behavior for the adorner.
  233.         /// </summary>
  234.         /// <param name="constraint">A size to constrain the adorner to.</param>
  235.         /// <returns>A <see cref="Size"/> object representing the amount of layout space needed by the adorner.</returns>
  236.         protected override Size MeasureOverride(Size constraint)
  237.         {
  238.             // Here's the secret to getting the adorner to cover the whole control
  239.             this.contentPresenter.Measure(Control.RenderSize);
  240.             return Control.RenderSize;
  241.         }
  242.  
  243.         /// <summary>
  244.         /// When overridden in a derived class, positions child elements and determines a size for a <see cref="FrameworkElement"/> derived class.
  245.         /// </summary>
  246.         /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param>
  247.         /// <returns>The actual size used.</returns>
  248.         protected override Size ArrangeOverride(Size finalSize)
  249.         {
  250.             this.contentPresenter.Arrange(new Rect(finalSize));
  251.             return finalSize;
  252.         }
  253.  
  254.         #endregion
  255.     }
  256. }
Advertisement
Add Comment
Please, Sign In to add comment