Watermark / hint text / placeholder TextBox

后端 未结 30 2526
遇见更好的自我
遇见更好的自我 2020-11-22 02:20

How can I put some text into a TextBox which is removed automatically when user types something in it?

30条回答
  •  粉色の甜心
    2020-11-22 02:47

    I saw John Myczek's solution, and its comments about Compatibility to ComboBox and PasswordBox, so I improved John Myczek's solution, and here it is:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Documents;
    
    /// 
    /// Class that provides the Watermark attached property
    /// 
    public static class WatermarkService
    {
        /// 
        /// Watermark Attached Dependency Property
        /// 
        public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
           "Watermark",
           typeof(object),
           typeof(WatermarkService),
           new FrameworkPropertyMetadata((object)null, new PropertyChangedCallback(OnWatermarkChanged)));
    
        #region Private Fields
    
        /// 
        /// Dictionary of ItemsControls
        /// 
        private static readonly Dictionary itemsControls = new Dictionary();
    
        #endregion
    
        /// 
        /// Gets the Watermark property.  This dependency property indicates the watermark for the control.
        /// 
        ///  to get the property from
        /// The value of the Watermark property
        public static object GetWatermark(DependencyObject d)
        {
            return (object)d.GetValue(WatermarkProperty);
        }
    
        /// 
        /// Sets the Watermark property.  This dependency property indicates the watermark for the control.
        /// 
        ///  to set the property on
        /// value of the property
        public static void SetWatermark(DependencyObject d, object value)
        {
            d.SetValue(WatermarkProperty, value);
        }
    
        /// 
        /// Handles changes to the Watermark property.
        /// 
        ///  that fired the event
        /// A  that contains the event data.
        private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Control control = (Control)d;
            control.Loaded += Control_Loaded;
    
            if (d is TextBox || d is PasswordBox)
            {
                control.GotKeyboardFocus += Control_GotKeyboardFocus;
                control.LostKeyboardFocus += Control_Loaded;
            }
            else if (d is ComboBox)
            {
                control.GotKeyboardFocus += Control_GotKeyboardFocus;
                control.LostKeyboardFocus += Control_Loaded;
                (d as ComboBox).SelectionChanged += new SelectionChangedEventHandler(SelectionChanged);
            }
            else if (d is ItemsControl)
            {
                ItemsControl i = (ItemsControl)d;
    
                // for Items property  
                i.ItemContainerGenerator.ItemsChanged += ItemsChanged;
                itemsControls.Add(i.ItemContainerGenerator, i);
    
                // for ItemsSource property  
                DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, i.GetType());
                prop.AddValueChanged(i, ItemsSourceChanged);
            }
        }
    
        /// 
        /// Event handler for the selection changed event
        /// 
        /// The source of the event.
        /// A  that contains the event data.
        private static void SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Control control = (Control)sender;
            if (ShouldShowWatermark(control))
            {
                ShowWatermark(control);
            }
            else
            {
                RemoveWatermark(control);
            }
        }
    
        #region Event Handlers
    
        /// 
        /// Handle the GotFocus event on the control
        /// 
        /// The source of the event.
        /// A  that contains the event data.
        private static void Control_GotKeyboardFocus(object sender, RoutedEventArgs e)
        {
            Control c = (Control)sender;
            if (ShouldShowWatermark(c))
            {
                RemoveWatermark(c);
            }
        }
    
        /// 
        /// Handle the Loaded and LostFocus event on the control
        /// 
        /// The source of the event.
        /// A  that contains the event data.
        private static void Control_Loaded(object sender, RoutedEventArgs e)
        {
            Control control = (Control)sender;
            if (ShouldShowWatermark(control))
            {
                ShowWatermark(control);
            }
        }
    
        /// 
        /// Event handler for the items source changed event
        /// 
        /// The source of the event.
        /// A  that contains the event data.
        private static void ItemsSourceChanged(object sender, EventArgs e)
        {
            ItemsControl c = (ItemsControl)sender;
            if (c.ItemsSource != null)
            {
                if (ShouldShowWatermark(c))
                {
                    ShowWatermark(c);
                }
                else
                {
                    RemoveWatermark(c);
                }
            }
            else
            {
                ShowWatermark(c);
            }
        }
    
        /// 
        /// Event handler for the items changed event
        /// 
        /// The source of the event.
        /// A  that contains the event data.
        private static void ItemsChanged(object sender, ItemsChangedEventArgs e)
        {
            ItemsControl control;
            if (itemsControls.TryGetValue(sender, out control))
            {
                if (ShouldShowWatermark(control))
                {
                    ShowWatermark(control);
                }
                else
                {
                    RemoveWatermark(control);
                }
            }
        }
    
        #endregion
    
        #region Helper Methods
    
        /// 
        /// Remove the watermark from the specified element
        /// 
        /// Element to remove the watermark from
        private static void RemoveWatermark(UIElement control)
        {
            AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
    
            // layer could be null if control is no longer in the visual tree
            if (layer != null)
            {
                Adorner[] adorners = layer.GetAdorners(control);
                if (adorners == null)
                {
                    return;
                }
    
                foreach (Adorner adorner in adorners)
                {
                    if (adorner is WatermarkAdorner)
                    {
                        adorner.Visibility = Visibility.Hidden;
                        layer.Remove(adorner);
                    }
                }
            }
        }
    
        /// 
        /// Show the watermark on the specified control
        /// 
        /// Control to show the watermark on
        private static void ShowWatermark(Control control)
        {
            AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);
    
            // layer could be null if control is no longer in the visual tree
            if (layer != null)
            {
                layer.Add(new WatermarkAdorner(control, GetWatermark(control)));
            }
        }
    
        /// 
        /// Indicates whether or not the watermark should be shown on the specified control
        /// 
        ///  to test
        /// true if the watermark should be shown; false otherwise
        private static bool ShouldShowWatermark(Control c)
        {
            if (c is ComboBox)
            {
                return (c as ComboBox).SelectedItem == null;
                //return (c as ComboBox).Text == string.Empty;
            }
            else if (c is TextBoxBase)
            {
                return (c as TextBox).Text == string.Empty;
            }
            else if (c is PasswordBox)
            {
                return (c as PasswordBox).Password == string.Empty;
            }
            else if (c is ItemsControl)
            {
                return (c as ItemsControl).Items.Count == 0;
            }
            else
            {
                return false;
            }
        }
    
        #endregion
    }
    

    Now, a ComboBox can be also Editable, and PasswordBox can add a watermark too. Don't forget to use JoanComasFdz's comment above to solve the margin problem.

    And, of course, All the credit goes to John Myczek.

提交回复
热议问题