WPF文本框实现placeholder效果
在WPF中,我们可以通过以下两种方式实现文本框的placeholder效果:
1. 使用Watermark
在WPF中,我们可以使用Watermark来实现文本框的placeholder效果。Watermark是一种帮助用户更好地理解文本框的提示信息,同时不会对用户的输入造成干扰的一种视觉效果。我们可以使用以下代码来实现Watermark:
<TextBox Text="{Binding Text, Mode=TwoWay}"
xmlns:local="clr-namespace:MyNamespace"
local:WatermarkService.Watermark="请输入文本"
local:WatermarkService.IsWatermarkEnabled="True" />
其中,"请输入文本"是我们要显示的placeholder文本,WatermarkService是我们自定义的一个附加属性类,用来实现Watermark效果。
以下是WatermarkService的代码:
public class WatermarkService : DependencyObject
{
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
"Watermark",
typeof(string),
typeof(WatermarkService),
new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty IsWatermarkEnabledProperty = DependencyProperty.RegisterAttached(
"IsWatermarkEnabled",
typeof(bool),
typeof(WatermarkService),
new FrameworkPropertyMetadata(false, IsWatermarkEnabledChanged));
public static string GetWatermark(DependencyObject obj)
{
return (string)obj.GetValue(WatermarkProperty);
}
public static void SetWatermark(DependencyObject obj, string value)
{
obj.SetValue(WatermarkProperty, value);
}
public static bool GetIsWatermarkEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsWatermarkEnabledProperty);
}
public static void SetIsWatermarkEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsWatermarkEnabledProperty, value);
}
private static void IsWatermarkEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox == null)
{
return;
}
if ((bool)e.NewValue)
{
textBox.GotFocus += TextBox_GotFocus;
textBox.LostFocus += TextBox_LostFocus;
UpdateWatermark(textBox);
}
else
{
textBox.GotFocus -= TextBox_GotFocus;
textBox.LostFocus -= TextBox_LostFocus;
RemoveWatermark(textBox);
}
}
private static void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null)
{
return;
}
RemoveWatermark(textBox);
}
private static void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null)
{
return;
}
UpdateWatermark(textBox);
}
private static void UpdateWatermark(TextBox textBox)
{
if (string.IsNullOrEmpty(textBox.Text))
{
textBox.Tag = textBox.Background;
textBox.Background = Brushes.Transparent;
textBox.Text = GetWatermark(textBox);
}
}
private static void RemoveWatermark(TextBox textBox)
{
if (textBox.Text == GetWatermark(textBox))
{
textBox.Text = string.Empty;
textBox.Background = (Brush)textBox.Tag;
}
}
}
2. 使用Style
我们也可以通过Style来实现文本框的placeholder效果。以下是实现方式:
<Style TargetType="TextBox" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="2" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true" />
<ScrollViewer x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
<TextBlock x:Name="PART_Watermark"
Text="{Binding Path=(local:WatermarkService.Watermark), RelativeSource={RelativeSource TemplatedParent}}"
Foreground="Gray"
Visibility="Collapsed"
IsHitTestVisible="false"
Margin="{TemplateBinding Padding}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter TargetName="border" Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" />
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="Text" Value="">
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
以上是两种实现方式的代码,你可以根据你的实际需求选择其中一种。希望本文对你有所帮助!