我希望我的文本框具有水印样式。 我有下面的代码https://stackoverflow.com/a/21672408/9928363
admin.py
我有很多文本框,我只想要一些使用这种风格但不是全部。 我该怎么做?
答案 0 :(得分:1)
有很多方法可以在文本框中添加水印,包括替换TextBox的ControlTemplate(正如您的问题所暗示的那样)。但是,替换TextBox的ControlTemplate可能并不理想,因为在这样做时,您将负责绘制整个控件,包括边框,样式化不同的状态等。这不是太困难(您可以使用Visual Studio或Espression Blend来复制来自当前主题的模板),但除非你做了很多工作,否则你将失去WPF功能,使常用控件的样式适应当前的Windows主题。
如果您想要一个不需要更改控件模板的简单,可重复使用的纯XAML方法,那么使用VisualBrush
声明样式资源是一种有效的方法。
见下文,我们有3个文本框,水印样式应用于其中两个。通过在文本框具有输入焦点时删除水印,此样式比示例更进一步。
<Window ...>
<Window.Resources>
<Style TargetType="TextBox" x:Key="Watermark">
<Style.Resources>
<VisualBrush x:Key="WatermarkBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="Enter Search Term Here" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
<Setter Property="Background" Value="{StaticResource WatermarkBrush}" />
</DataTrigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Width="250" VerticalAlignment="Center" FontSize="20"
HorizontalAlignment="Left" Style="{StaticResource Watermark}"/>
<TextBox Width="250" VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<TextBox Width="250" VerticalAlignment="Center"
HorizontalAlignment="Left" Style="{StaticResource Watermark}"/>
</StackPanel>
</Window>
如果您需要水印来对不同的字体大小做出反应,您可以使用Stretch
属性: -
<VisualBrush x:Key="WatermarkBrush" AlignmentX="Left" AlignmentY="Center" Stretch="Uniform">
<VisualBrush.Visual>
<Label Padding="2 1" Content="Enter Search Term Here" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
答案 1 :(得分:0)
如先前的回答中所述,有时最好不要替换标准控件的ControlTemplate。因此,这是一种通过附加属性创建水印的方法,该方法可以使现有控件模板保持完整。这样做的好处是您可以将水印设置为任何文本,包括在运行时通过数据绑定进行设置。
为演示起见,XAML将创建3个文本框(请参见下文)。底部文本框具有一个水印,其Text属性绑定到顶部文本框的Text属性,从而演示了水印文本的动态性质。在第二个文本框中键入数字将更改底部文本框的文本(和水印)的字体大小。
以上图片取自Windows 10标准主题。将Windows主题设置为“高对比度”后,这里再次出现。如您所见,已经尊重了现有的ControlTemplate(和配色方案)。
XAML
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:behaviors="clr-namespace:WpfApp2.Behaviors"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Watermark" Grid.Row="0"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="5"
x:Name="watermark" Width="250" HorizontalAlignment="Left" Text="enter search term here"/>
<Label Content="Font Size" Grid.Row="1"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="5"
x:Name="fontSize" Width="250" VerticalAlignment="Center" HorizontalAlignment="Left"
behaviors:TextBoxExtensions.Watermark="Enter a font size"/>
<Label Content="Result" Grid.Row="2"/>
<TextBox Grid.Row="2" Grid.Column="2" Margin="5"
Width="200" VerticalAlignment="Center" HorizontalAlignment="Left"
FontSize="{Binding Text, ElementName=fontSize}"
behaviors:TextBoxExtensions.Watermark="{Binding Path=Text, ElementName=watermark}" />
</Grid>
</Window>
TextBoxExtensions.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApp2.Behaviors
{
public class TextBoxExtensions
{
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
"Watermark",
typeof(string),
typeof(TextBoxExtensions),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnWatermarkTextChanged)
);
private static void OnWatermarkTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tb = d as TextBox;
if (tb != null)
{
var textChangedHandler = new TextChangedEventHandler((s, ea) => ShowOrHideWatermark(s as TextBox));
var focusChangedHandler = new DependencyPropertyChangedEventHandler((s, ea) => ShowOrHideWatermark(s as TextBox));
var sizeChangedHandler = new SizeChangedEventHandler((s, ea) => ShowOrHideWatermark(s as TextBox));
if (string.IsNullOrEmpty(e.OldValue as string))
{
tb.TextChanged += textChangedHandler;
tb.IsKeyboardFocusedChanged += focusChangedHandler;
// We need SizeChanged events because the Background brush is sized according to the control size
tb.SizeChanged += sizeChangedHandler;
}
if (string.IsNullOrEmpty(e.NewValue as string))
{
tb.TextChanged -= textChangedHandler;
tb.IsKeyboardFocusedChanged -= focusChangedHandler;
tb.SizeChanged -= sizeChangedHandler;
}
ShowOrHideWatermark(tb);
}
}
public static string GetWatermark(DependencyObject element)
{
return (string)element.GetValue(WatermarkProperty);
}
public static void SetWatermark(DependencyObject element, string value)
{
element.SetValue(WatermarkProperty, value);
}
private static void ShowOrHideWatermark(TextBox tb)
{
// Restore TextBox background to style/theme value
tb.ClearValue(TextBox.BackgroundProperty);
if (string.IsNullOrEmpty(tb.Text) && !tb.IsKeyboardFocused)
{
var wm = GetWatermark(tb);
if (!string.IsNullOrEmpty(wm))
{
tb.Background = CreateTextBrush(wm, tb);
}
}
}
private static Brush CreateTextBrush(string text, TextBox tb)
{
Grid g = new Grid
{
Background = tb.Background,
Width = tb.ActualWidth,
Height = tb.ActualHeight
};
g.Children.Add(new Label
{
Padding = new Thickness(2,1,1,1),
FontSize = tb.FontSize,
FontFamily = tb.FontFamily,
Foreground = Brushes.LightGray,
Content = text
});
VisualBrush vb = new VisualBrush
{
Visual = g,
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Center,
};
return vb;
}
}
}
任何一种水印机制都不适合每种情况。此特定解决方案的优点是保留了默认主题,将使用TextBox的字体大小和系列,并且将通过样式或主题遵守TextBox控件上设置的背景颜色。但是,如果尝试直接在XAML中设置TextBox的Background属性,它将无法正常工作,因为该值将被水印清除。