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


107

例如,当文本框为空时,Facebook在“搜索”文本框中具有“搜索”提示文本。

如何使用WPF文本框实现此目标?

Facebook的搜索文本框


2
尝试搜索“提示横幅”。
默认语言环境

@MAKKAM,此MSDN文章对此进行了讨论,但未显示它是如何完成的
Louis Rhys


1
我不会称呼您要求的“提示文字”。对我来说,提示文字是一个弹出窗口。但是,当我要设置占位符文本时发现了这个问题。下面的答案帮助了我。
史蒂夫,

1
顺便说一下,这就是水印
Blechdose

Answers:


158

您可以使用VisualBrush和中的一些触发器来轻松完成此操作Style

<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 2012年

5
如果有人想知道如何使用附加属性来提高样式的可重用性,请参阅:stackoverflow.com/a/650620/724944
surfen 2012年

@Kurian IsMouseCaptured只会使提示仅在您用鼠标单击时消失,而在释放鼠标按钮时会再次出现。看起来不太好。IsMouseOver也不会很好(键盘具有焦点,但鼠标指针位于其他位置=>提示显示)。大多数提示横幅都使用IsKeyboardFocused(例如Facebook),我认为这很好。替代解决方案是同时使用两个触发器:(IsMouseOver或IsKeyboardFocused)
2012年

23
解决方案应该是Hint =“请输入您的文本”,而不是20个元素... A,传奇的内置文本框不支持此...
Mzn 2014年

8
尽管此方法对于默认情况可能没问题,但是当您的文本框已经包含背景画笔或者表单背景的颜色与文本框的颜色不同时,此方法将无效。
LWChris

56

这是我从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}}" />
        <!-- enter term here -->
        <TextBox MinWidth="50" Name="txtSearchBox" Background="Transparent" />
    </Grid>

有趣的方法我不会马上想到自己。
itsmatt

漂亮又简单:)
shmulik.r

3
如果您将TextBlock设置为IsHitTestVisible="False"
Mage Xy,

1
@MageXy引用第一个TextBlock(提示一个)。
菲利克斯

如果要将提示文本绑定到属性,此解决方案效果很好。
PeterB


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";
        }
    }
}

7
-1在后面的代码中执行:会使控件混乱,并且很有可能会干扰其他控制逻辑(如果不是现在那么将来)。
AlexeiOst,2016年


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;
    }
}

我找到的最好和最简单的解决方案!谢谢!!
史蒂夫,

2

我曾经遇到过同样的情况,我按照以下方式解决了。我仅满足提示框的要求,您可以通过在其他事件(例如焦点等)上添加效果和其他东西来使其更具交互性。

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;
        }
    }


0

我使用了失去焦点的事件:

Private Sub txtSearchBox_GotFocus(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles txtSearchBox.GotFocus
    If txtSearchBox.Text = "Search" Then
        txtSearchBox.Text = ""
    Else

    End If

End Sub

Private Sub txtSearchBox_LostFocus(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles txtSearchBox.LostFocus
    If txtSearchBox.Text = "" Then
        txtSearchBox.Text = "Search"
    Else

    End If
End Sub

它工作正常,但文本仍为灰色。需要清理。我正在使用VB.NET


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>

0

这是我的看法:

<ControlTemplate>
    <Grid>
        <Grid.Resources>
            <!--Define look / layout for both TextBoxes here. I applied custom Padding and BorderThickness for my application-->
            <Style TargetType="TextBox">
                <Setter Property="Padding" Value="4"/>
                <Setter Property="BorderThickness" Value="2"/>
            </Style>
        </Grid.Resources>

        <TextBox x:Name="TbSearch"/>
        <TextBox x:Name="TbHint" Text="Suche" Foreground="LightGray"
                 Visibility="Hidden" IsHitTestVisible="False" Focusable="False"/>
    </Grid>

    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition SourceName="TbSearch" Property="Text" Value="{x:Static sys:String.Empty}"/>
                <Condition SourceName="TbSearch" Property="IsKeyboardFocused" Value="False"/>
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter TargetName="TbHint" Property="Visibility" Value="Visible"/>
            </MultiTrigger.Setters>
        </MultiTrigger>

        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition SourceName="TbSearch" Property="Text" Value="{x:Null}"/>
                <Condition SourceName="TbSearch" Property="IsKeyboardFocused" Value="False"/>
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter TargetName="TbHint" Property="Visibility" Value="Visible"/>
            </MultiTrigger.Setters>
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

在我看来,包括最高答案在内的大多数其他答案都有缺陷。

该解决方案在所有情况下均适用。纯XAML,易于重用。


-1

我做到这一点了VisualBrush,并在一些触发器Style所建议的:sellmeadog

<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>

@sellmeadog:应用程序正在运行,bt设计未加载...出现以下错误: 模糊类型引用。名为“ StaticExtension”的类型至少出现在两个名称空间中:“ MS.Internal.Metadata.ExposedTypes.Xaml”和“ System.Windows.Markup”。考虑调整程序集XmlnsDefinition属性。 使用的是.net 3.5


通过更改<Trigger Property="Text" Value="{x:Static sys:String.Empty}"><Trigger Property="Text" Value="">
SUHAIL AG

6
这似乎是对另一则帖子的回应。请仅发布问题的完整解决方案作为答案。
德鲁·盖诺

4
如果您认为@sellmeadog的答案几乎正确,请考虑对其进行纠正,而不要发布几乎没有差异的新答案。
0xBADF00D 2015年

-11

对于WPF,没有办法。您必须模仿它。请参阅此示例。第二种方法(不稳定的解决方案)是承载一个WinForms用户控件,该控件继承自TextBox,并将EM_SETCUEBANNER消息发送到编辑控件。即。

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam);

private const Int32 ECM_FIRST = 0x1500;
private const Int32 EM_SETCUEBANNER = ECM_FIRST + 1;

private void SetCueText(IntPtr handle, string cueText) {
    SendMessage(handle, EM_SETCUEBANNER, IntPtr.Zero, Marshal.StringToBSTR(cueText));
}

public string CueText {
    get {
        return m_CueText;
    } 
    set {
        m_CueText = value;
        SetCueText(this.Handle, m_CueText);
}

另外,如果您想托管WinForm控件方法,我有一个已经包含此实现的框架称为BitFlex Framework,您可以在此处免费下载

这是一篇文章如果您需要更多信息,有关BitFlex。您将开始发现,如果您希望拥有Windows资源管理器样式的控件,而这些控件通常永远不会开箱即用,并且由于WPF通常无法使用句柄,因此您无法围绕Win32或现有控件编写简单的包装器与WinForms。

屏幕截图: 在此处输入图片说明


1
哇,这看起来有点骇人听闻。用XAML创建用户控件时该怎么做?
路易·瑞斯,

你不知道 这是完成的方式。如果要封装它,则创建一个用户控件和一个CueText属性,然后在setter中调用SetCueText。
大卫·安德森

我想OP应该使用Winforms控件来使用这种方法。还是有一种获取文本框句柄的方法?
默认语言环境

这似乎可以用WPF声明性地完成,可以通过绑定文本框是否具有焦点等来实现。-上面的示例更多是WinForms方法-可以在WPF中工作,但是不正确方式。
BrainSlugs83

1
抱歉,这个答案是不正确的。同样,所有链接都断开了。
Forest Kunecke
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.