为什么我的自定义 WPF 文本框控件不显示此水印? [英] Why is my custom WPF text box control not displaying this watermark?
问题描述
我在名为 CustomControls
的新 WPF 项目中完成了以下操作.
I have done the following in a new WPF project titled CustomControls
.
步骤 1:创建一个 Controls
文件夹.添加了一个名为 WatermarkTextBox.cs
的新文件.在文件中添加了此 C# 代码:
Step 1: Created a Controls
folder. Added a new file titled WatermarkTextBox.cs
to it. Added this C# code in the file:
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:
Step 2: Within the Controls
folder, added a new file titled WatermarkTextBox.xaml
. Added this XAML in the file:
<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:
Step 3: Create a Themes
folder. Add a new file titled Generic.xaml
to it. Add this XAML in the file:
<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
:
Step 4: In MainWindow.xaml
: Added xmlns:controls="clr-namespace:Controls"
, and defined a new WatermarkTextBox
:
<controls:WatermarkTextBox x:Name="Hostname" Height="40" FontFamily="Segoe UI" FontSize="20" VerticalContentAlignment="Center" Watermark="Hello, world."/>
我看到此自定义控件所基于的文本框,但没有看到我为其扩展的水印.为什么会这样,我该如何渲染我的水印?附言我应该注意到,如果我将 XAML 中的 {Binding Watermark}
更改为硬编码字符串,水印确实会显示.此外,如果我调试我的代码,我会看到 WatermarkTextBox
选择正确的值......那么为什么 XAML 不显示它?怎么会有人调试这些东西?
I see the text box that this custom control is based upon, but I don't see the watermark which I've extended for it. Why is that, and how may I render my watermark? P.S. I should note that the watermark DOES show up if I change {Binding Watermark}
in the XAML to a hard-coded string. Also, if I debug my code I see that WatermarkTextBox
picks up the correct value...so why is the XAML not displaying it? How can someone even debug this stuff?
推荐答案
诀窍是使用名为 Blend for Visual Studio 的 Windows 应用程序来编辑现有 WatermarkTextBox<的默认模板/code> 并扩展它以引入一个
Grid
,它不仅包括内容滚动视图,还包括一个新标签来放置水印.总之,我必须对 WatermarkTextBox.xaml
进行此更改:
The trick was to use the Windows application titled Blend for Visual Studio to edit the default template of the existing WatermarkTextBox
and extend it to introduce a Grid
which includes not only the content scroll view but also a new label to house the watermark. In all, I had to make this change to 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
相同的位置以编程方式显示和隐藏标签会更容易,因为大多数黑客或扩展程序就是这样做的.
Edit: If you're thinking about doing this in production, think again. I thought to myself, "Oh, it would be so nice to extend every control I need to provide functionality like this." Well unfortunately some control classes such as the PasswordBox
are sealed, making this a moot point in those situations. In fact it would just be easier to programmatically show and hide a label in the same location as your TextBox
, as most hacks or extensions do just that.
这篇关于为什么我的自定义 WPF 文本框控件不显示此水印?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!