WPF带占位符的TextBox

Posted lonelyxmas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

    }
}

以上是关于WPF带占位符的TextBox的主要内容,如果未能解决你的问题,请参考以下文章

WPF 实现带标题的TextBox

WPF 自定义控件并使用(例如带水印和字体图标的文本框)

使用jquery在空输入字段中获取占位符的值?

WPF Xaml更改TextBox触发器更改前景

Sass之继承,混合宏,占位符的用法总结

具有许多占位符的 ItemStack