我在一个名为CustomControls
的新WPF项目中完成了以下工作。
第1步:创建了Controls
文件夹。添加了一个名为WatermarkTextBox.cs
的新文件。在文件中添加了这个C#代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public class WatermarkTextBox : TextBox
{
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(String), typeof(WatermarkTextBox), new PropertyMetadata(String.Empty));
public String Watermark
{
get { return (String)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
}
}
}
第2步:在Controls
文件夹中,添加了一个名为WatermarkTextBox.xaml
的新文件。在文件中添加了此XAML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Controls">
<Style TargetType="{x:Type controls:WatermarkTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Resources>
<VisualBrush x:Key="WatermarkBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="{Binding Watermark}" FontFamily="Segoe UI" FontSize="20" Foreground="LightGray" Padding="5" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource WatermarkBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource WatermarkBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
第3步:创建Themes
文件夹。添加一个标题为Generic.xaml
的新文件。在文件中添加此XAML:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/CustomControls;component/Controls/WatermarkTextBox.xaml" />
</ResourceDictionary.MergedDictionaries>
第4步:在MainWindow.xaml
中:添加了xmlns:controls="clr-namespace:Controls"
,并定义了新的WatermarkTextBox
:
<controls:WatermarkTextBox x:Name="Hostname" Height="40" FontFamily="Segoe UI" FontSize="20" VerticalContentAlignment="Center" Watermark="Hello, world."/>
我看到此自定义控件所基于的文本框,但我看不到我为其扩展的水印。为什么这样,我怎么能渲染我的水印?附:我应该注意,如果我将XAML中的{Binding Watermark}
更改为硬编码字符串,则会显示水印。此外,如果我调试我的代码,我看到WatermarkTextBox
获取正确的值...那么为什么XAML不显示它?有人甚至可以调试这些东西吗?
答案 0 :(得分:0)
诀窍是使用名为 Blend for Visual Studio 的Windows应用程序来编辑现有WatermarkTextBox
的默认模板,并将其扩展为引入Grid
,其中不包括只有内容滚动视图,但也有一个新的标签来容纳水印。总之,我不得不对WatermarkTextBox.xaml
进行此更改:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:controls="clr-namespace:Controls">
<Style TargetType="{x:Type controls:WatermarkTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:WatermarkTextBox">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<Label Cursor="IBeam" Visibility="Hidden" x:Name="WatermarkText" Content="{TemplateBinding Watermark}" FontFamily="Segoe UI" FontSize="20" Foreground="LightGray" Padding="5" />
</Grid>
</Border>
<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>
<Trigger Property="Text" Value="{x:Static system:String.Empty}">
<Setter Property="Visibility" Value="Visible" TargetName="WatermarkText" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible" TargetName="WatermarkText" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
编辑:如果您正考虑在制作中执行此操作,请再想一想。我心想,“哦,扩展我需要的所有控件来提供这样的功能真是太好了。”不幸的是,PasswordBox
等一些控制类是密封,这在这些情况下成为一个有争议的问题。 事实上,以TextBox
在同一位置以编程方式显示和隐藏标签会更容易,因为大多数黑客或扩展都会这样做。