Come posso aggiungere un testo di suggerimento alla casella di testo WPF?


107

Ad esempio, Facebook ha un testo di suggerimento "Cerca" nella casella di testo Cerca quando la casella di testo è vuota.

Come ottenere questo risultato con le caselle di testo WPF ??

Casella di testo di ricerca di Facebook


2
Prova a cercare "banner cue".
locale predefinito

@MAKKAM questo articolo di MSDN ne discute ma non mostra come è fatto
Louis Rhys


1
Non chiamerei quello che chiedi "testo di suggerimento". per me il testo del suggerimento è una finestra popup. tuttavia ho trovato questa domanda quando volevo impostare il testo segnaposto. e le risposte di seguito mi hanno aiutato.
steve

1
A proposito, si chiama filigrana
Blechdose

Risposte:


158

Puoi farlo molto più facilmente con a VisualBrushe alcuni trigger in a 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>

Per aumentare la riutilizzabilità di questo Style, puoi anche creare un insieme di proprietà allegate per controllare il testo, il colore, l'orientamento, ecc.


1
Usa IsMouseCaptured invece di IsKeyboardFocused. Ecco come risponde un vero stendardo.
Monstieur

5
Se qualcuno si è chiesto come utilizzare le proprietà allegate per aumentare la riusabilità dello stile, vedere: stackoverflow.com/a/650620/724944
naviga il

@Kurian IsMouseCaptured farà scomparire la stecca solo quando fai clic con il mouse, ma apparirà di nuovo quando rilasci il pulsante del mouse. Non sembra buono. Anche IsMouseOver non andrebbe bene (la tastiera ha il focus ma il puntatore del mouse è altrove => cue visualizzato). La maggior parte dei banner di cue utilizza IsKeyboardFocused (Facebook ad esempio) e penso che vada bene. Una soluzione alternativa sarebbe quella di utilizzare entrambi i trigger: (IsMouseOver OR IsKeyboardFocused)
naviga il

23
La soluzione dovrebbe essere Suggerimento = "Inserisci il tuo testo" non 20 elementi ... Ahimè, questo non è supportato dalla leggendaria casella di testo incorporata ...
Mzn

8
Sebbene questo approccio possa andare bene per le condizioni predefinite, non funziona quando la casella di testo contiene già un pennello per lo sfondo o lo sfondo del modulo non è dello stesso colore della casella di testo.
LWChris

56

Questa è la mia semplice soluzione, adattata da 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>

Approccio interessante a cui non avrei pensato subito.
martedì

bello e semplice :)
shmulik.r

3
Questa soluzione funziona particolarmente bene se imposti TextBlock suIsHitTestVisible="False"
Mago Xy

1
@MageXy si riferisce al primo TextBlock (il suggerimento).
Felix

Questa soluzione funziona alla grande se desideri associare il testo del suggerimento a una proprietà.
PeterB

11

che dire dell'utilizzo di materialDesign HintAssist? Sto usando questo che puoi anche aggiungere anche un suggerimento mobile:

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

Ho installato Material Design con il pacchetto Nuget, c'è una guida all'installazione nel link della documentazione


2
Libreria molto utile
AlexF11

9

Fallo nel code-behind impostando inizialmente il colore del testo su grigio e aggiungendo gestori di eventi per ottenere e perdere lo stato attivo della tastiera.

TextBox tb = new TextBox();
tb.Foreground = Brushes.Gray;
tb.Text = "Text";
tb.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_GotKeyboardFocus);
tb.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_LostKeyboardFocus);

Quindi i gestori di eventi:

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 per farlo in code behind: ingombra il controllo e c'è un'alta probabilità che questo interferisca con altre logiche di controllo, se non ora e poi in futuro.
Alexei,


4

Puoi farlo in un modo molto semplice. L'idea è di posizionare un'etichetta nello stesso posto della casella di testo. La tua etichetta sarà visibile se la casella di testo non ha testo e non ha il focus.

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

Bonus: se vuoi avere un valore predefinito per il tuo textBox, assicurati di impostarlo dopo aver inviato i dati (ad esempio: "InputText" = "PlaceHolder Text Here" se vuoto).


2

Un altro approccio ;-)

funziona anche con PasswordBox. Se vuoi usarlo con TextBox, scambia semplicemente PasswordChangedcon 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>

codebehind:

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

La soluzione migliore e più semplice che ho trovato !! Grazie!!
steve

2

Una volta sono entrato nella stessa situazione, l'ho risolto in questo modo. Ho soddisfatto solo i requisiti di una casella di suggerimento, puoi renderla più interattiva aggiungendo effetti e altre cose su altri eventi come il focus ecc.

CODICE WPF (ho rimosso lo stile per renderlo leggibile)

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

Codice 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

Ho usato gli eventi di messa a fuoco ottenuta e persa:

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

Funziona bene, ma il testo è ancora in grigio. Ha bisogno di essere ripulito. Stavo usando 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

Questa è la mia opinione:

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

La maggior parte delle altre risposte, inclusa quella in alto, hanno dei difetti secondo me.

Questa soluzione funziona in tutte le circostanze. XAML puro, facilmente riutilizzabile.


-1

Compio questo con un VisualBrushe alcuni trigger in un Stylesuggerito da: 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: Applicazione in esecuzione, bt Design non si carica ... viene visualizzato il seguente errore: Riferimento di tipo ambiguo. Un tipo denominato "StaticExtension" è presente in almeno due spazi dei nomi, "MS.Internal.Metadata.ExposedTypes.Xaml" e "System.Windows.Markup". Valutare la possibilità di modificare gli attributi XmlnsDefinition dell'assembly. sto usando .net 3.5


Risolto il problema passando <Trigger Property="Text" Value="{x:Static sys:String.Empty}">a<Trigger Property="Text" Value="">
SUHAIL AG

6
Questa sembra essere una risposta a un altro post. Pubblica solo soluzioni complete alla domanda come risposte.
Drew Gaynor

4
Se pensi che la risposta di @ sellmeadog sia quasi corretta, valuta la possibilità di correggerla, invece di pubblicare una nuova risposta quasi senza differenze.
0xBADF00D

-11

Per WPF, non c'è un modo. Devi imitarlo. Vedi questo esempio . Una soluzione secondaria (traballante) consiste nell'ospitare un controllo utente WinForms che eredita da TextBox e inviare il messaggio EM_SETCUEBANNER al controllo di modifica. vale a dire.

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

Inoltre, se vuoi ospitare un approccio di controllo WinForm, ho un framework che include già questa implementazione chiamata BitFlex Framework, che puoi scaricare gratuitamente qui .

Ecco un articolo su BitFlex se desideri maggiori informazioni. Inizierai a scoprire che se stai cercando di avere controlli in stile Windows Explorer che questo generalmente non viene mai fuori dalla scatola, e poiché WPF non funziona con gli handle generalmente non puoi scrivere un semplice wrapper attorno a Win32 o un controllo esistente come puoi con WinForms.

Immagine dello schermo: inserisci qui la descrizione dell'immagine


1
wow, sembra un po 'hacker .. Come posso farlo quando creo un controllo utente con XAML?
Louis Rhys

Non lo fai. Ecco come si fa. Se vuoi incapsularlo, crea un controllo utente e una proprietà CueText e chiama SetCueText nel setter.
David Anderson

Immagino che l'OP dovrebbe ospitare i controlli winforms, per utilizzare questo approccio. O c'è un modo per ottenere l'handle della casella di testo?
locale predefinito

Sembra qualcosa che potrebbe essere fatto in modo dichiarativo con WPF, legandosi al fatto che la casella di testo sia attiva o meno, ecc. - L'esempio sopra è più un approccio WinForms - funzionerà in WPF, ma non è corretto modo.
BrainSlugs83

2
Spiacenti, ma questa risposta è semplicemente errata. Inoltre tutti i collegamenti sono interrotti.
Forest Kunecke
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.