在WPF中需要显示水印的效果,有时候需要显示在TextBox上显示类似水印的灰色提示文本占位符效果来作为提醒信息类似如下效果:
图1. 水印显示的效果
要实现这样的效果有很多办法,这里介绍一个最简单的,就是在TextBox上叠加一个TextBlock来实现这个功能,这里对比显示完全的实现过程:
- 原始的没有占位符效果的代码如下:
<StackPanel Orientation="Horizontal">
<Label Content="Print Ran_ge:"/>
<TextBox Text="{Binding PrintRange, UpdateSourceTrigger=PropertyChanged}" MinWidth="300" VerticalContentAlignment="Center" ToolTip="Serial number in format: 1,3-5,8" />
</StackPanel>
- 是轻松实现两个控件叠加的效果,Grid是最简单直接的,要显示在上面的注意放在Grid里的后面部分,越前面越在底层,这里TextBlock在TextBox的后面,所以它显示在TextBox的上面,就出现了如上图1的效果:
<StackPanel Orientation="Horizontal" >
<Label Content="Print Ran_ge:"/>
<Grid>
<TextBox Text="{Binding PrintRange, UpdateSourceTrigger=PropertyChanged}" MinWidth="300" VerticalContentAlignment="Center" ToolTip="Serial number in format: 1,3-5,8" />
<TextBlock Text="Serial number in format: 1,3-5,8" Visibility="{Binding ShowPrintRangeWaterMark}" VerticalAlignment="Center" Foreground="Gray" Padding="5,0" IsHitTestVisible="False"/>
</Grid>
</StackPanel>
上面代码两个要点:
a. <TextBox Text="{Binding PrintRange, UpdateSourceTrigger=PropertyChanged}",这个让属性改变的触发实时发生,而不是在TextBox失去焦点才发生。
b. <TextBlock Text="Serial number in format: 1,3-5,8" Visibility="{Binding ShowPrintRangeWaterMark}" VerticalAlignment="Center" Foreground="Gray" Padding="5,0" IsHitTestVisible="False"/>,加粗部分让TextBlock不响应任何点击或者输入事件,它悬浮在那里,但它不影响下面的TextBox的键盘鼠标的操作。
- 功能的实现,功能的实现我们是通过两个控件绑定的两个属性来实现的,一个是TextBox的
Text
属性,它绑定了其视图模型的PrintRange
属性,一个是TextBlock的Visibility
属性,它绑定了其视图模型的ShowPrintRangeWaterMark
属性。
代码很简单,打开视图模型的类,添加两个上面提到的属性:
private string _printRange;
public string PrintRange
{
get => _printRange;
set
{
_printRange = value;
OnPropertyChanged(nameof(PrintRange));
OnPropertyChanged(nameof(ShowPrintRangeWaterMark));
}
}
public Visibility ShowPrintRangeWaterMark => string.IsNullOrEmpty(_printRange) ? Visibility.Visible : Visibility.Collapsed;
需要注意的是,这个视图模型一定要实现INotifyPropertyChanged
接口,就是要这些代码:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}