WPF中WatermarkTextBox(水印文本框)的实现

本文介绍如何在WPF中实现一个带有水印的文本框,包括类的定义、水印属性的设置以及XAML模板的配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们经常能在很多设计中看到当文本框为空的时候显示灰色斜体的提示性文字,这样可以省略文本框前的标签说明,同时也会使设计变得美观。在html中我们只需要给input加上placeholder就行了,那么在wpf中怎么做呢?

首先我继承System.Windows.Controls.TextBox实现WatermarkTextBox的类,并添加一个Watermark的string属性,用于设置水印文字。

WatermarkTextBox.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Tenshi.Common.Wpf.Controls
{
    public class WatermarkTextBox : TextBox
    {
        private string watermark = string.Empty;
        public string Watermark
        {
            get { return watermark; }
            set { watermark = value ?? string.Empty; }
        }

        public static readonly DependencyProperty WatermarkProperty =
            DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkTextBox));

        static WatermarkTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WatermarkTextBox),
                new FrameworkPropertyMetadata(typeof(WatermarkTextBox)));
        }

        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);

            if (this.Text == string.Empty)
            {
                VisualStateManager.GoToState(this, "Empty", true);
            }
            else
            {
                VisualStateManager.GoToState(this, "NotEmpty", true);
            }
        }
    }
}

这里为WatermarkTextBox添加了两种VisualState,文本为空时进入Empty状态,非空进入NotEmpty状态。

TextStates.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tenshi.Common.Wpf.Controls
{
    public enum TextStates
    {
        /// <summary>
        /// 内容为空
        /// </summary>
        Empty,
        /// <summary>
        /// 内容不为空
        /// </summary>
        NotEmpty
    }
}

接下来在xaml中设置WatermarkTextBox的Template

Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Tenshi.Common.Wpf.Controls">
    <ControlTemplate x:Key="WatermarkTextBoxTemplate" TargetType="local:WatermarkTextBox">
        <Grid>
            <TextBlock x:Name="WatermarkText" Text="{TemplateBinding Watermark}" FontFamily="{TemplateBinding FontFamily}"
                       FontSize="{TemplateBinding FontSize}"
                       FontWeight="{TemplateBinding FontWeight}"
                       FontStyle="Italic"
                       Foreground="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"
                       Opacity="1.0"
                       Margin="{TemplateBinding Padding}"/>
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
            </Border>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="TextStates">
                    <VisualState x:Name="NotEmpty">
                        <Storyboard>
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="WatermarkText"
                                                           Storyboard.TargetProperty="Opacity">
                                <DiscreteDoubleKeyFrame KeyTime="0" Value="0.0"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="Empty">
                        <Storyboard>
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="WatermarkText"
                                                           Storyboard.TargetProperty="Opacity">
                                <DiscreteDoubleKeyFrame KeyTime="0" Value="1.0"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="Opacity" TargetName="border" Value="0.56"/>
            </Trigger>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
            </Trigger>
            <Trigger Property="IsKeyboardFocused" Value="True">
                <Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <Style TargetType="local:WatermarkTextBox">
        <Setter Property="Template" Value="{StaticResource WatermarkTextBoxTemplate}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="BorderBrush" Value="#FF007ACC"/>
    </Style>
</ResourceDictionary>


大家可以看到所谓的水印就是我加进去的一个叫WatermarkText的TextBlock,当进入Empty状态时,我让他的Opacity = 1.0,这时候就会显示水印;当进入NotEmpty状态时,他的Opacity = 0.0,这时候水印就会隐藏。

最后配一张效果图:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值