我该如何在WPF文本框中添加提示文本?

131
例如,Facebook在搜索文本框为空时,在搜索文本框内显示“搜索”提示文字。
如何在WPF文本框中实现类似功能? Facebook的搜索文本框

2
尝试搜索“提示横幅”。 - default locale
2
请参考以下链接:https://dev59.com/dXRA5IYBdhLWcg3wxA5N - OneWorld
1
我不会称你所要求的为“提示文本”。对我来说,提示文本是一个弹出窗口。尽管如此,当我想设置占位符文本时,我发现了这个问题,并且下面的答案帮助了我。 - steve
1
顺便说一下,那被称为水印。 - Welcor
这个回答解决了你的问题吗?水印/提示文本/占位符文本框 - StayOnTarget
显示剩余2条评论
14个回答

183

您可以通过VisualBrushStyle中的一些触发器更轻松地实现此目标:

<TextBox>
    <TextBox.Style>
        <Style TargetType="TextBox" xmlns:sys="clr-namespace:System;assembly=mscorlib">
            <Style.Resources>
                <VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
                    <VisualBrush.Visual>
                        <Label Content="Search" Foreground="LightGray" />
                    </VisualBrush.Visual>
                </VisualBrush>
            </Style.Resources>
            <Style.Triggers>
                <Trigger Property="Text" Value="{x:Static sys:String.Empty}">
                    <Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
                </Trigger>
                <Trigger Property="Text" Value="{x:Null}">
                    <Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
                </Trigger>
                <Trigger Property="IsKeyboardFocused" Value="True">
                    <Setter Property="Background" Value="White" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

为了增加这个Style的可重用性,您还可以创建一组附加属性来控制实际提示横幅文本、颜色、方向等。


1
使用IsMouseCaptured而不是IsKeyboardFocused。这就是一个真正的提示横幅的响应方式。 - Monstieur
6
如果有人想知道如何使用附加属性来增加样式的可重用性,请查看:https://dev59.com/yUbRa4cB1Zd3GeqP4d-K#650620。 - surfen
@sellmeadog:可以请您看一下我的问题http://stackoverflow.com/questions/18843737/attached-property-with-watermark-textbox吗?我尝试添加一个附加属性,但是无法使其正常工作。 - Rolfi
27
解决方案应该是Hint="请输入您的文本"而不是20个元素...遗憾的是,这在传奇内置的文本框中不受支持... - Lzh
8
虽然这种方法在默认情况下可能还可以,但是当你的文本框已经包含背景刷或表单背景颜色与文本框不同时,它就行不通了。 - LWChris
显示剩余9条评论

70

这是我从 Microsoft (https://code.msdn.microsoft.com/windowsapps/How-to-add-a-hint-text-to-ed66a3c6) 改编的简单解决方案。

    <Grid Background="White" HorizontalAlignment="Right" VerticalAlignment="Top"  >
        <!-- overlay with hint text -->
        <TextBlock Margin="5,2" MinWidth="50" Text="Suche..." 
                   Foreground="LightSteelBlue" Visibility="{Binding ElementName=txtSearchBox, Path=Text.IsEmpty, Converter={StaticResource MyBoolToVisibilityConverter}}" IsHitTestVisible="False"/>
        <!-- enter term here -->
        <TextBox MinWidth="50" Name="txtSearchBox" Background="Transparent" />
    </Grid>

有趣的方法,我自己一开始并没有想到。 - itsmatt
5
如果您将TextBlock设置为IsHitTestVisible="False",这个解决方案会特别有效。 - Mage Xy
1
@MageXy 此处指的是第一个 TextBlock(即提示文本块)。 - Felix
1
什么是MyBoolToVisibilityConverter? - steve
1
@steve 例如,在您的资源标记中添加以下代码:<BooleanToVisibilityConverter x:Key="MyBoolToVisibilityConverter" /> - Slate
显示剩余7条评论

18

使用MaterialDesign HintAssist怎么样?我正在使用这个工具,它还可以添加浮动提示:

<TextBox Width="150" Height="40" Text="hello" materialDesign:HintAssist.Hint="address"  materialDesign:HintAssist.IsFloating="True"></TextBox>

我使用Nuget Package安装了Material Design,安装指南在文档链接中。


4
非常有用的库。 - AlexF11

9
在代码后端完成,将文本颜色最初设置为灰色,并添加获得和失去键盘焦点的事件处理程序。
TextBox tb = new TextBox();
tb.Foreground = Brushes.Gray;
tb.Text = "Text";
tb.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_GotKeyboardFocus);
tb.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_LostKeyboardFocus);

那么接下来是事件处理程序:

private void tb_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    if(sender is TextBox)
    {
        //If nothing has been entered yet.
        if(((TextBox)sender).Foreground == Brushes.Gray)
        {
            ((TextBox)sender).Text = "";
            ((TextBox)sender).Foreground = Brushes.Black;
        }
    }
}


private void tb_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    //Make sure sender is the correct Control.
    if(sender is TextBox)
    {
        //If nothing was entered, reset default text.
        if(((TextBox)sender).Text.Trim().Equals(""))
        {
            ((TextBox)sender).Foreground = Brushes.Gray;
            ((TextBox)sender).Text = "Text";
        }
    }
}

12
在代码后端执行此操作会使控件混乱,并且很有可能会干扰其他控件逻辑,无论是现在还是将来。 - AlexeiOst

5

2
不鼓励仅提供链接的答案。 - Josh Noe

4
我曾经遇到过相同的情况,我是这样解决的。 我只满足了提示框的要求,你可以通过在其他事件上添加效果和其他东西(如焦点等)来使其更具交互性。 WPF 代码(我已删除样式以使其可读)。
<Grid Margin="0,0,0,0"  Background="White">
    <Label Name="adminEmailHint" Foreground="LightGray" Padding="6"  FontSize="14">Admin Email</Label>
    <TextBox Padding="4,7,4,8" Background="Transparent" TextChanged="adminEmail_TextChanged" Height="31" x:Name="adminEmail" Width="180" />
</Grid>
<Grid Margin="10,0,10,0" Background="White" >
    <Label Name="adminPasswordHint" Foreground="LightGray" Padding="6"  FontSize="14">Admin Password</Label>
    <PasswordBox Padding="4,6,4,8" Background="Transparent" PasswordChanged="adminPassword_PasswordChanged" Height="31" x:Name="adminPassword" VerticalContentAlignment="Center" VerticalAlignment="Center" Width="180" FontFamily="Helvetica" FontWeight="Light" FontSize="14" Controls:TextBoxHelper.Watermark="Admin Password"  FontStyle="Normal" />
</Grid>

C# 代码

private void adminEmail_TextChanged(object sender, TextChangedEventArgs e)
    {
        if(adminEmail.Text.Length == 0)
        {
            adminEmailHint.Visibility = Visibility.Visible;
        }
        else
        {
            adminEmailHint.Visibility = Visibility.Hidden;
        }
    }

private void adminPassword_PasswordChanged(object sender, RoutedEventArgs e)
    {
        if (adminPassword.Password.Length == 0)
        {
            adminPasswordHint.Visibility = Visibility.Visible;
        }
        else
        {
            adminPasswordHint.Visibility = Visibility.Hidden;
        }
    }

4
你可以用非常简单的方法实现。 思路是在与你的文本框相同的位置放置一个标签。如果文本框没有文本并且没有焦点,你的标签将可见。
 <Label Name="PalceHolder"  HorizontalAlignment="Left" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Height="40" VerticalAlignment="Top" Width="239" FontStyle="Italic"  Foreground="BurlyWood">PlaceHolder Text Here
  <Label.Style>
    <Style TargetType="{x:Type Label}">
      <Setter Property="Visibility" Value="Hidden"/>
      <Style.Triggers>
        <MultiDataTrigger>
          <MultiDataTrigger.Conditions>
            <Condition Binding ="{Binding ElementName=PalceHolder, Path=Text.Length}" Value="0"/>
            <Condition Binding ="{Binding ElementName=PalceHolder, Path=IsFocused}" Value="False"/>
          </MultiDataTrigger.Conditions>
          <Setter Property="Visibility" Value="Visible"/>
        </MultiDataTrigger>
      </Style.Triggers>
    </Style>
  </Label.Style>
</Label>
<TextBox  Background="Transparent" Name="TextBox1" HorizontalAlignment="Left" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Height="40"TextWrapping="Wrap" Text="{Binding InputText,Mode=TwoWay}" VerticalAlignment="Top" Width="239" />

奖励:如果您想为文本框设置默认值,请确保在提交数据后进行设置(例如:如果为空,则“InputText”=“PlaceHolder Text Here”)。


2

还有一种方法 ;-)

这也适用于PasswordBox。如果你想使用它与TextBox一起使用,只需将PasswordChanged替换为TextChanged

XAML:

<Grid>
    <!-- overlay with hint text -->
    <TextBlock Margin="5,2"
                Text="Password"
                Foreground="Gray"
                Name="txtHintPassword"/>
    <!-- enter user here -->
    <PasswordBox Name="txtPassword"
                Background="Transparent"
                PasswordChanged="txtPassword_PasswordChanged"/>
</Grid>

代码后台:

private void txtPassword_PasswordChanged(object sender, RoutedEventArgs e)
{
    txtHintPassword.Visibility = Visibility.Visible;
    if (txtPassword.Password.Length > 0)
    {
        txtHintPassword.Visibility = Visibility.Hidden;
    }
}

我找到的最好、最简单的解决方案!谢谢! - steve
你不应该添加 IsHitTestVisible="False" 确保无论用户单击哪里,都将转发到正确的控件吗? - JTIM
@JTIM 当然你可以这么做,但是因为PasswordBox是XAML中的最后一个控件,所以它应该处于Z索引的“顶部”-> 单击始终会聚焦到passwordbox,而且据我所知TextBlock不能聚焦->文本框(或Passwordbox)将获得焦点。由于答案已经三年了,我不是100%确定它是如何工作的,但确实有效;-) - Mat

1

另一种解决方案是使用 WPF 工具包,例如 MahApps.Metro。它有许多不错的功能,比如文本框水印:

Controls:TextBoxHelper.Watermark="Search..."

请查看http://mahapps.com/controls/textbox.html


0
  <Grid>
    <TextBox Name="myTextBox"/>
    <TextBlock>
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=myTextBox, Path=Text.IsEmpty}" Value="True">
                        <Setter Property="Text" Value="Prompt..."/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</Grid>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接