这是一个奇怪的问题:
我有一个继承自TextBox
的自定义控件,并提供" ghost"文本 - 例如它说"用户名"在一个盒子里,直到你在里面点击它,然后"鬼"文本消失,用户可以输入他们的用户名。
"幽灵文字"对于控件而言,它只是TextBox子类中的属性。然后,只要相关,我就会TextBox.Text
设置它。
在Visual Studio WPF XAML预览窗口(标准UI设计窗口)中,我希望能够预览" "幽灵文字" - 就像设置文本框的实际文本一样,您可以在预览中看到它,而不仅仅是在运行应用程序时。
我尝试将Text
属性设置为OnInitialised
函数中的相关Ghost文本,但它对预览没有任何影响。
我应该在哪里放置影响设计器中控件预览的代码?
奖金问题:我所说的是什么名字"鬼"文本框?很高兴知道未来!
答案 0 :(得分:2)
我称之为“鬼”文本框的实际名称是什么?对未来来说,上帝会是神!
我在描述其目的时看到这被称为“暗示”,或者在描述其外观时被称为“水印”。我倾向于使用前者,因为它描述了函数,它更符合WPF设计理念:实际表示由模板决定,概念“提示”可以不同方式呈现只需应用自定义样式/模板即可。当有人选择以另一种方式呈现它时,为什么暗示它应该是水印呢?
设计方面,我认为你正在以错误的方式接近这一点。我会这样实现这样一种方式,即TextBox
以外的控制可以更容易地选择:使用附加属性。
我会创建一个静态类,比如HintProperties
,它声明了几个附加的依赖属性:
Hint
- 声明提示内容;通常是一个字符串,但它不一定是。它可能只是object
,类似于Content
的{{1}}属性。
ContentControl
- 计算的只读HasHint
属性,在bool
更改时重新评估,并简单指示控件是否指定了Hint
。用作Hint
条件,可在控件模板中切换提示演示者的可见性。
然后,为Trigger
(或其他控件)提供自定义样式,该样式将TextBox
演示者覆盖在常规内容的顶部,默认情况下隐藏。当控件具有键盘焦点时,添加触发器以降低提示的不透明度,而当Hint
为空字符串时,添加另一个触发器以提示提示Visible
。
如果你真的想要全力以赴,你可以投入Text
和HintTemplate
属性。
但是,如果这看起来有点过分,您只需在派生的HintTemplateSelector
类上直接声明Hint
或Watermark
属性即可。我不会尝试通过有条件地更改TextBox
属性来实现此功能,因为这会干扰数据绑定,并且可能会影响值优先级。
答案 1 :(得分:0)
您可以使用通常在App.xaml
中声明的样式以可重复使用的方式执行此操作。在此样式中,您将控件模板替换为您自己的实现,并将一些控件包装在一起。基本上,您使用透明背景从正常WatermarkTextBox
组成TextBox
,并在TextBlock
后面放置TextBox
控件和标准文字。此Visibility
的{{1}}使用特定的TextBlock
绑定到TextBox
,因此当TextInputToVisibilityConverter
包含文字或只有焦点时它会消失。
虽然这可能看起来像很多代码,但您可以定义一次这样的代码,只需设置TextBox
某些资源的声明
TextBox
风格宣言:
xmlns:c="clr-namespace:YourNameSpace.Converters"
<SolidColorBrush x:Key="brushWatermarkBackground" Color="White" />
<SolidColorBrush x:Key="brushWatermarkForeground" Color="LightSteelBlue" />
<c:TextInputToVisibilityConverter x:Key="TextInputToVisibilityConverter" />
<Style x:Key="SearchTextBox" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid Background="{StaticResource brushWatermarkBackground}">
<TextBlock Margin="5,5" Text="Search..."
Foreground="{StaticResource brushWatermarkForeground}" >
<TextBlock.Visibility>
<MultiBinding
Converter="{StaticResource TextInputToVisibilityConverter}">
<Binding RelativeSource="{RelativeSource
Mode=FindAncestor, AncestorType=TextBox}"
Path="Text.IsEmpty" />
<Binding RelativeSource="{RelativeSource
Mode=FindAncestor, AncestorType=TextBox}"
Path="IsFocused" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
<Border x:Name="Border" Background="Transparent"
BorderBrush="{DynamicResource SolidBorderBrush}"
BorderThickness="1" Padding="2" CornerRadius="2">
<!-- The implementation places the Content into the
ScrollViewer. It must be named PART_ContentHost
for the control to function -->
<ScrollViewer Margin="0" x:Name="PART_ContentHost"
Style="{DynamicResource SimpleScrollViewer}"
Background="Transparent"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
的实现,只需要文本输入,转换为bool并将其转换为TextInputToVisibilityConverter
。同时考虑到焦点。
Visibility
现在所有的基础设施都已到位。在你的view / usercontrol / window中只是改变了Textbox的样式,那就是你的水印文本框..
namespace YourNameSpace
{
public class TextInputToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values,
Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (values[0] is bool && values[1] is bool)
{
bool hasText = !(bool)values[0];
bool hasFocus = (bool)values[1];
if (hasFocus || hasText)
return Visibility.Collapsed;
}
return Visibility.Visible;
}
public object[] ConvertBack(object value,
Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}