我在这篇文章How can I add a hint text to WPF textbox?中发现了一个内联样式,我喜欢在文本框的背景中添加提示文本。我用它在Text 1节中创建了一个带有控件模板的样式<Window.Resources>:
<Window
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"
Name="Window" Title="MainWindow" Height="120" Width="1000">
<Window.Resources>
<Style x:Key="Text1" TargetType="{x:Type TextBox}" >
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="BorderThickness" Value="2,2,2,2" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Margin" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}" xmlns:sys="clr-namespace:System;assembly=mscorlib" >
<ControlTemplate.Resources>
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="Whity" Color="White" />
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="This is a hint text" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
<Storyboard x:Key="SrcWrongInput" TargetName="Src" >
<ColorAnimation Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)" To="Red" AutoReverse="True" RepeatBehavior="4x" Duration="0:0:0:0.3"/>
</Storyboard>
</ControlTemplate.Resources>
<Border Name="Border" CornerRadius="2" Padding="2" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter TargetName="Border" Property="Background" Value="{StaticResource CueBannerBrush}"/>
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter TargetName="Border" Property="Background" Value="{StaticResource CueBannerBrush}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource Whity}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="5*" />
<RowDefinition Height="5*" />
</Grid.RowDefinitions>
<TextBox Name="Src" Grid.Column="0" Grid.Row="0" Style="{StaticResource Text1}" ToolTip="Enter path to exe or folder C:\Program Files\..." VerticalContentAlignment="Center" />
<TextBox Name="Name" Grid.Column="1" Grid.Row="0" Style="{StaticResource Text1}" ToolTip="Enter name" VerticalContentAlignment="Center"/>
<TextBox Name="Rslt" Grid.Column="0" Grid.Row="1" Style="{StaticResource Text1}" ToolTip="Result of procedure" VerticalContentAlignment="Center">
<TextBox.Resources>
<Storyboard x:Key="RsltWrongInput" TargetName="Rslt" >
<ColorAnimation Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)" To="Red" AutoReverse="True" RepeatBehavior="4x" Duration="0:0:0:0.3"/>
</Storyboard>
</TextBox.Resources>
</TextBox>
<Button Name="Do" Grid.Column="2" Grid.Row="0" />
</Grid>
</Grid>
它加载了这个ps1脚本:
Add-Type -AssemblyName presentationframework
[xml]$XAML = Get-Content "MainWindowStack.xaml"
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
$DataContextRslt = New-Object System.Collections.ObjectModel.ObservableCollection[Object]
$do.Add_Click({
$rsltWrongInputStory = $Rslt.Resources["RsltWrongInput"]
$rsltWrongInputStory.begin()
})
$Form.ShowDialog() | out-null
它加载并显示提示文本,一旦文本不为空或文本框获得键盘焦点,提示文本就会消失,这正是我想要的行为。但是我无法将VisualBrush x:Key=“CueBannerBrush”中的标签内容绑定到文本框的另一个属性(例如,标记或工具提示)或DataContext以使提示文本可调整。我尝试了各种不同的Binding / TemplateBinding表达式,使用relativeSource,祖先,没有结果。
我还看了其他关于这个主题的文章:在Parameterized style to display hint text in WPF TextBox [duplicate]中,有一个关于如何以及为什么这不能工作的评论,后面是这个链接将占位符文本添加到文本框中,其中有一个不同方法的示例:
<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Panel.ZIndex="2" />
<TextBox Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
它确实有效,使用这种风格,我可以使用文本框的Tag属性设置提示文本,但它有一个限制,即它不像第一个那样对键盘焦点做出React,提示文本只有在输入字母后才会消失。
我尝试使用此触发器添加该行为失败:
<DataTrigger Binding="{Binding Path=IsKeyboardFocused, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="LightGray"/>
</DataTrigger>
第一种样式还有一个问题,当尝试将VerticalContentAlignment=“Center”添加到setter时,Window不再加载,因此我将其单独添加到每个文本框。还有另外两个问题,其中执行的故事板“SrcWrongInput”,我添加到源的风格。首先,我不知道如何在样式资源中解决它,所以我还将其添加到名为“Rslt”的最后一个文本框的资源中,以至少确保它与样式兼容。它不是,我在ps1脚本中的按钮“Do”点击处理程序上触发了它,并得到了这个异常:
“BorderBrush-Eigenschaft wird nicht auf“DependencyObject”im Pfad“(BorderBrush).(0)”verwiesen.”
BorderBrush属性未链接到路径(BorderBrush)处的依赖项对象。(0)
1条答案
按热度按时间ycggw6v21#
第一个示例使用
VisualBrush
呈现提示文本。相反,您应该使用TextBlock
覆盖原始文本站点。出于性能原因,通常不建议使用Label
并将Label.Content
属性绑定到string
。相反,您应该使用高度优化的TextBlock
控件来显示简单的文本。您的第二个解决方案实现了对
TextBox
非常糟糕的理解。使用内部TextBox
实现TextBlock
的Controltemplate
没有意义。除了毫无意义之外,当你想处理模板化的TextBox
的文本或输入事件时,你会遇到奇怪的行为:因为用户在内部的TextBox
中输入,所以相关事件不会像预期的那样被引发(在模板化的TextBox
上)。推荐的解决方案是用
TextBlock
覆盖ControlTemnplate
中的文本站点。然后可以将TextBlock.Text
属性绑定到模板化的TextBox
(例如TextBox.Tag
或专用的自定义属性)。使用
CollectionView.IsEmpty
属性作为触发器来切换提示TextBlock
的可见性。这避免了两个单独的触发器来检查空的string
或null
。一个
MultiTrigger
或在这种情况下一个MultiDataTrigger
允许合并文本空和焦点条件,以进一步简化模板。为了避免丢失TextBox
的自定义,您应该使用TemplateBinding
扩展并将内部属性(如Border.Background
)绑定到模板化的TextBox
属性(例如TextBox.Background
属性)。最后,设置默认值,例如
TextBox.Background
使用Style
设置器:这样你就可以自定义/覆盖控件,而不需要创建一个新的ControlTemplate
: