c#笔记--WPF文本框和密码框添加水印效果(背景文字提示)

时间:2022-03-03 06:14:28

文本框(TextBox)水印效果

显示效果:
c#笔记--WPF文本框和密码框添加水印效果(背景文字提示)

方法一:验证触发器填充VisualBrush

创建一个可视画刷VisualBrush,使用触发器验证一下Text是否为空,使用VisualBrush填充TextBox的背景色

<TextBox Height="25" Width="180" HorizontalAlignment="Center" Margin="0 50 0 0">
    <TextBox.Resources>
        <VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.3" Stretch="None" AlignmentX="Left">
            <VisualBrush.Visual>
                <TextBlock Text="请输入账号"/>
            </VisualBrush.Visual>
        </VisualBrush>
    </TextBox.Resources>
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Text" Value="">
                    <Setter Property="Background" Value="{StaticResource HelpBrush}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

方法二:判断鼠标焦点填充SolidColorBrush

判断TextBox获取到焦点时文字消失,失去焦点时文字显示,在后台使用SolidColorBrush画刷填充
XAML代码(添加TextBox获取到焦点和失去焦点的事件):

<TextBox Name="tbxUser" GotFocus="TbxUser_GotFocus" Foreground="LightGray" LostFocus="TbxUser_LostFocus"
         Height="25" Width="180" HorizontalAlignment="Center" Margin="0 20 0 0"></TextBox>

后台代码(由于窗口刚加载时没有判断焦点,所以在窗口加载时初始化填充,然后判断捕捉到鼠标焦点时取消填充,失去焦点时判断是否输入了文字,没输入则再次填充):

public MainWindow()
{
    InitializeComponent();
    tbxUser.Text = "请输入账号";
    SolidColorBrush scb = new SolidColorBrush(Colors.LightGray);
    tbxUser.Foreground = scb;
}
private void TbxUser_GotFocus(object sender, RoutedEventArgs e)
{
    tbxUser.Text = "";
    SolidColorBrush scb = new SolidColorBrush(Colors.Black);
    tbxUser.Foreground = scb;
}

private void TbxUser_LostFocus(object sender, RoutedEventArgs e)
{
    if (string.IsNullOrEmpty(tbxUser.Text))
    {
        tbxUser.Text = "请输入账号";
        SolidColorBrush scb = new SolidColorBrush(Colors.LightGray);
        tbxUser.Foreground = scb;
    }
}

两种方法的区别在于第一种鼠标点击TextBox时提示文字不会消失,当输入文字时才消失,第二种方法则是鼠标点击TextBox时则提示文字消失

密码框(PasswordBox)水印效果

显示效果:
c#笔记--WPF文本框和密码框添加水印效果(背景文字提示)

由于密码框没有可以用于判断输入值非空的依赖属性,于是我们添加一个PasswordBoxMonitor类来监测密码框是否为空,继承与DependencyObject类;通过PasswordLength属性来判断密码框输入的内容长度是否为0来显示水印
需要引入的命名空间:

using System.Windows;
using System.Windows.Controls;

PasswordBoxMonitor类代码:

public class PasswordBoxMonitor : DependencyObject
{
    public static bool GetIsMonitoring(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsMonitoringProperty);
    }

    public static void SetIsMonitoring(DependencyObject obj, bool value)
    {
        obj.SetValue(IsMonitoringProperty, value);
    }

    public static readonly DependencyProperty IsMonitoringProperty =
        DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(PasswordBoxMonitor), new UIPropertyMetadata(false, OnIsMonitoringChanged));



    public static int GetPasswordLength(DependencyObject obj)
    {
        return (int)obj.GetValue(PasswordLengthProperty);
    }

    public static void SetPasswordLength(DependencyObject obj, int value)
    {
        obj.SetValue(PasswordLengthProperty, value);
    }

    public static readonly DependencyProperty PasswordLengthProperty =
        DependencyProperty.RegisterAttached("PasswordLength", typeof(int), typeof(PasswordBoxMonitor), new UIPropertyMetadata(0));

    private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var pb = d as PasswordBox;
        if (pb == null)
        {
            return;
        }
        if ((bool)e.NewValue)
        {
            pb.PasswordChanged += PasswordChanged;
        }
        else
        {
            pb.PasswordChanged -= PasswordChanged;
        }
    }

    static void PasswordChanged(object sender, RoutedEventArgs e)
    {
        var pb = sender as PasswordBox;
        if (pb == null)
        {
            return;
        }
        SetPasswordLength(pb, pb.Password.Length);
    }
}

创建好类之后再使用重构的PasswordBox,需要在window中引用

xmlns:PasswordStyle="clr-namespace:你的项目名"

之后在PasswordBox样式中重写ControlTemplate 方法,添加一个TextBox覆盖掉密码框,当输入文字之后隐藏掉TextBox
XAML代码:

<PasswordBox VerticalAlignment="Center" Name="pb" HorizontalAlignment="Center"  
             VerticalContentAlignment="Center" Height="30"  Width="220"
             Margin="0 10 0 0">
        <PasswordBox.Style>
        <Style TargetType="PasswordBox">
            <Setter Property="Height" Value="23"></Setter>
            <Setter Property="HorizontalAlignment" Value="Left"></Setter>
            <Setter Property="VerticalAlignment" Value="Top"></Setter>
            <Setter Property="PasswordStyle:PasswordBoxMonitor.IsMonitoring"  Value="True"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type PasswordBox}">
                        <Border Name="Bd"  Background="{TemplateBinding Background}"  BorderThickness="{TemplateBinding BorderThickness}"
                   BorderBrush="{TemplateBinding BorderBrush}"  SnapsToDevicePixels="true">
                            <Grid>
                                <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                <StackPanel Orientation="Horizontal" Visibility="Collapsed" Name="myStackPanel">
                                    <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="LightGray" Text=" 请输入密码"/>
                                </StackPanel>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Visibility" TargetName="myStackPanel" Value="Collapsed"/>
                            </Trigger>
                            <Trigger Property="PasswordStyle:PasswordBoxMonitor.PasswordLength" Value="0">
                                <Setter Property="Visibility" TargetName="myStackPanel" Value="Visible"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </PasswordBox.Style>
</PasswordBox>

提示:写完之后可能会提示命名空间找不到,有时候是编译器没刷新过来,尝试编译运行一下就好了
♪(^∀^●)ノ