天天看點

WPF帶占位符的TextBox簡介原理帶占位符的文本框使用附加屬性

原文: WPF帶占位符的TextBox

簡介

效果圖如下:

WPF帶占位符的TextBox簡介原理帶占位符的文本框使用附加屬性

使用的XAML代碼如下:

<Window x:Class="PlaceHolderTextBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:PlaceHolderTextBox"
        Title="MainWindow"
        Width="525"
        Height="350">
    <StackPanel>
        <local:PlaceholderTextBox Placeholder="查詢" />
        <TextBox x:Name="TxtTest" local:PlaceholderManager.Placeholder="搜尋" />
    </StackPanel>
</Window>      

其中第一個是帶占位符的文本框,第二個使用附加屬性裝飾在現有的文本框上。

原理

将一個與占位符綁定的TextBlock放入VisualBrush内,在TextBox的Text為空時使用VisualBrush繪制背景,不為空時背景設為Null。

正因為如此,如果文本框設定了背景,使用此方法就會覆寫原有的背景。但一般不會設定TextBox的背景。

帶占位符的文本框

代碼較簡單,如下:

using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace PlaceHolderTextBox
{
    /// <summary>
    /// 帶點位符的文本輸入控件
    /// </summary>
    public class PlaceholderTextBox:TextBox
    {
        #region Fields

        /// <summary>
        /// 占位符的文本框
        /// </summary>
        private readonly TextBlock _placeholderTextBlock = new TextBlock();

        /// <summary>
        /// 占位符的畫刷
        /// </summary>
        private readonly VisualBrush _placeholderVisualBrush = new VisualBrush();

        #endregion Fields

        #region Properties

        /// <summary>
        /// 占位符的依賴屬性
        /// </summary>
        public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.Register(
            "Placeholder", typeof (string), typeof (PlaceholderTextBox),
            new FrameworkPropertyMetadata("請在此輸入", FrameworkPropertyMetadataOptions.AffectsRender));

        /// <summary>
        /// 占位符
        /// </summary>
        public string Placeholder
        {
            get { return (string) GetValue(PlaceholderProperty); }
            set { SetValue(PlaceholderProperty, value); }
        }

        #endregion Properties

        #region Public Methods

        public PlaceholderTextBox()
        {
            var binding = new Binding
            {
                Source = this,
                Path = new PropertyPath("Placeholder")
            };
            _placeholderTextBlock.SetBinding(TextBlock.TextProperty, binding);
            _placeholderTextBlock.FontStyle = FontStyles.Italic;

            _placeholderVisualBrush.AlignmentX = AlignmentX.Left;
            _placeholderVisualBrush.Stretch = Stretch.None;
            _placeholderVisualBrush.Visual = _placeholderTextBlock;

            Background = _placeholderVisualBrush;
            TextChanged += PlaceholderTextBox_TextChanged;
        }

        #endregion Public Methods

        #region Events Handling

        /// <summary>
        /// 文本變化的響應
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlaceholderTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            Background = string.IsNullOrEmpty(Text) ? _placeholderVisualBrush : null;
        }

        #endregion Events Handling

    }
}      

使用附加屬性

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace PlaceHolderTextBox
{
    /// <summary>
    /// 占位符的管理類
    /// </summary>
    public class PlaceholderManager
    {
        #region Fields

        /// <summary>
        /// 文本框和Visual畫刷對應的字典
        /// </summary>
        private static readonly Dictionary<TextBox, VisualBrush> TxtBrushes = new Dictionary<TextBox, VisualBrush>();

        #endregion Fields

        #region Attached DependencyProperty

        /// <summary>
        /// 占位符的附加依賴屬性
        /// </summary>
        public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
            "Placeholder", typeof(string), typeof(PlaceholderManager),
            new PropertyMetadata("請在此處輸入", OnPlaceholderChanged));

        /// <summary>
        /// 擷取占位符
        /// </summary>
        /// <param name="obj">占位符所在的對象</param>
        /// <returns>占位符</returns>
        public static string GetPlaceholder(DependencyObject obj)
        {
            return (string)obj.GetValue(PlaceholderProperty);
        }

        /// <summary>
        /// 設定占位符
        /// </summary>
        /// <param name="obj">占位符所在的對象</param>
        /// <param name="value">占位符</param>
        public static void SetPlaceholder(DependencyObject obj, string value)
        {
            obj.SetValue(PlaceholderProperty, value);
        }

        #endregion Attached DependencyProperty

        #region Events Handling

        /// <summary>
        /// 占位符改變的響應
        /// </summary>
        /// <param name="d">來源</param>
        /// <param name="e">改變資訊</param>
        public static void OnPlaceholderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var txt = d as TextBox;
            if ((txt != null) && (!TxtBrushes.ContainsKey(txt)))
            {
                var placeholderTextBlock = new TextBlock();
                var binding = new Binding
                {
                    Source = txt,
                    //綁定到附加屬性
                    Path = new PropertyPath("(0)", PlaceholderProperty)
                };
                placeholderTextBlock.SetBinding(TextBlock.TextProperty, binding);
                placeholderTextBlock.FontStyle = FontStyles.Italic;

                var placeholderVisualBrush = new VisualBrush
                {
                    AlignmentX = AlignmentX.Left,
                    Stretch = Stretch.None,
                    Visual = placeholderTextBlock
                };

                txt.Background = placeholderVisualBrush;

                txt.TextChanged += PlaceholderTextBox_TextChanged;
                txt.Unloaded += PlaceholderTextBox_Unloaded;

                TxtBrushes.Add(txt, placeholderVisualBrush);
            }
        }

        /// <summary>
        /// 文本變化的響應
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void PlaceholderTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            var txt = sender as TextBox;
            if ((txt != null) && (TxtBrushes.ContainsKey(txt)))
            {
                var placeholderVisualBrush = TxtBrushes[txt];
                txt.Background = string.IsNullOrEmpty(txt.Text) ? placeholderVisualBrush : null;
            }
        }

        /// <summary>
        /// 文本框解除安裝的響應
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void PlaceholderTextBox_Unloaded(object sender, RoutedEventArgs e)
        {
            var txt = sender as TextBox;
            if ((txt != null) && (TxtBrushes.ContainsKey(txt)))
            {
                TxtBrushes.Remove(txt);

                txt.TextChanged -= PlaceholderTextBox_TextChanged;
                txt.Unloaded -= PlaceholderTextBox_Unloaded;
            }
        }

        #endregion Events Handling

    }
}