Wie kann ich dem WPF-Textfeld einen Hinweistext hinzufügen?


107

Facebook hat beispielsweise einen Hinweistext "Suchen" im Textfeld "Suchen", wenn das Textfeld leer ist.

Wie erreicht man das mit WPF-Textfeldern?

Facebooks Suchtextfeld


2
Versuchen Sie, nach "Cue-Banner" zu suchen.
Standardgebietsschema

@ MAKKAM Dieser MSDN-Artikel beschreibt es, aber es zeigt nicht, wie es gemacht wird
Louis Rhys


1
Ich würde nicht nennen, was Sie nach "Hinweistext" fragen. Für mich ist Hinweis Text ein Popup-Fenster. Trotzdem fand ich diese Frage, als ich Platzhaltertext einrichten wollte. und die Antworten unten haben mir geholfen.
Steve

1
Das nennt man übrigens Wasserzeichen
Blechdose

Antworten:


158

Sie können dies viel einfacher mit a VisualBrushund einigen Auslösern in a erreichen 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>

Um die Wiederverwendbarkeit zu verbessern Style, können Sie auch eine Reihe von angehängten Eigenschaften erstellen, um den tatsächlichen Text, die Farbe, die Ausrichtung usw. des Cue-Banners zu steuern.


1
Verwenden Sie IsMouseCaptured anstelle von IsKeyboardFocused. So reagiert ein echtes Cue-Banner.
Monstieur

5
Wenn sich jemand gefragt hat, wie angehängte Eigenschaften verwendet werden können, um die Wiederverwendbarkeit des Stils zu verbessern,
lesen

@Kurian IsMouseCaptured lässt den Cue nur verschwinden, wenn Sie mit der Maus darauf klicken, wird jedoch wieder angezeigt, wenn Sie die Maustaste loslassen. Es sieht nicht gut aus. IsMouseOver wäre auch nicht gut (Tastatur hat Fokus, aber Mauszeiger ist woanders => Cue angezeigt). Die meisten Cue-Banner verwenden IsKeyboardFocused (z. B. Facebook) und ich denke, es ist in Ordnung. Eine alternative Lösung wäre, beide Trigger zu verwenden: (IsMouseOver OR IsKeyboardFocused)
surfen

23
Die Lösung sollte sein Hinweis = "Bitte geben Sie Ihren Text ein" nicht 20 Elemente ... Leider wird dies nicht durch das legendäre eingebaute Textfeld unterstützt ...
Mzn

8
Während dieser Ansatz für Standardbedingungen in Ordnung sein kann, funktioniert er nicht, wenn Ihr Textfeld bereits einen Hintergrundpinsel enthält oder der Formularhintergrund nicht dieselbe Farbe wie das Textfeld hat.
LWChris

56

Dies ist meine einfache Lösung, angepasst von 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>

Interessanter Ansatz, an den ich nicht sofort gedacht hätte.
itsmatt

nett und einfach :)
shmulik.r

3
Diese Lösung funktioniert besonders gut, wenn Sie den TextBlock aufIsHitTestVisible="False"
Mage Xy

1
@MageXy bezieht sich auf den ersten TextBlock (den Hinweis).
Felix

Diese Lösung eignet sich hervorragend, wenn Sie den Hinweistext an eine Eigenschaft binden möchten.
PeterB

11

Was ist mit materialDesign HintAssist? Ich benutze dies, was Sie auch schwebende Hinweise hinzufügen können:

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

i installierte Material Design mit Nuget Paket dort Installationsanleitung in ist Dokumentation Link


2
Sehr nützliche Bibliothek
AlexF11

10

Tun Sie dies im Code-Behind, indem Sie die Textfarbe zunächst auf Grau setzen und Ereignishandler hinzufügen, um den Tastaturfokus zu gewinnen und zu verlieren.

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

Dann die Event-Handler:

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

6
-1 für die Ausführung im Code dahinter: Überfrachtet die Steuerung, und es besteht eine hohe Wahrscheinlichkeit, dass dies andere Steuerlogiken stört, wenn nicht jetzt, dann in Zukunft.
AlexeiOst


4

Sie können dies auf sehr einfache Weise tun. Die Idee ist, ein Etikett an der gleichen Stelle wie Ihr Textfeld zu platzieren. Ihr Etikett wird angezeigt, wenn das Textfeld keinen Text und keinen Fokus enthält.

 <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: Wenn Sie einen Standardwert für Ihre TextBox haben möchten, müssen Sie diesen nach dem Senden von Daten festlegen (zum Beispiel: "InputText" = "PlaceHolder Text Here", falls leer).


2

Ein anderer Ansatz ;-)

das funktioniert auch mit PasswordBox. Wenn Sie es mit verwenden möchten TextBox, tauschen Sie es einfach PasswordChangedmit aus 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;
    }
}

Beste und einfachste Lösung, die ich gefunden habe !! Vielen Dank!!
Steve

2

Ich bin einmal in die gleiche Situation geraten und habe sie folgendermaßen gelöst. Ich habe nur die Anforderungen eines Hinweisfelds erfüllt. Sie können es interaktiver gestalten, indem Sie Effekte und andere Dinge zu anderen Ereignissen wie Fokus usw. hinzufügen.

WPF-CODE (Ich habe das Styling entfernt, um es lesbar zu machen)

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

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

Ich habe die Ereignisse zum Erhalten und Verlieren des Fokus verwendet:

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

Es funktioniert gut, aber der Text ist immer noch grau. Muss aufgeräumt werden. Ich habe VB.NET verwendet


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

Das ist meine Meinung:

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

Die meisten anderen Antworten, einschließlich der obersten, weisen meiner Meinung nach Mängel auf.

Diese Lösung funktioniert unter allen Umständen. Pure XAML, leicht wiederverwendbar.


-1

Ich erreiche dies mit einem VisualBrushund einigen Auslösern in einem StyleVorschlag von : 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: Anwendung läuft, bt Design wird nicht geladen ... der folgende Fehler tritt auf: Mehrdeutige Typreferenz . Ein Typ mit dem Namen 'StaticExtension' kommt in mindestens zwei Namespaces vor: 'MS.Internal.Metadata.ExposedTypes.Xaml' und 'System.Windows.Markup'. Ziehen Sie in Betracht, die XmlnsDefinition-Attribute der Assembly anzupassen. Ich verwende .net 3.5


Das Problem wurde durch den Wechsel <Trigger Property="Text" Value="{x:Static sys:String.Empty}">zu<Trigger Property="Text" Value="">
SUHAIL AG

6
Dies scheint eine Antwort auf einen anderen Beitrag zu sein. Bitte veröffentlichen Sie nur vollständige Lösungen für die Frage als Antworten.
Drew Gaynor

4
Wenn Sie der Meinung sind, dass die Antwort von @ sellmeadog nahezu korrekt ist, sollten Sie sie korrigieren, anstatt eine neue Antwort ohne Unterschied zu veröffentlichen.
0xBADF00D

-11

Für WPF gibt es keinen Weg. Du musst es nachahmen. Siehe dieses Beispiel . Eine sekundäre (flockige Lösung) besteht darin, ein WinForms-Benutzersteuerelement zu hosten, das von TextBox erbt, und die Nachricht EM_SETCUEBANNER an das Bearbeitungssteuerelement zu senden. dh.

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

Wenn Sie einen WinForm-Steuerungsansatz hosten möchten, habe ich bereits ein Framework namens BitFlex Framework, das diese Implementierung enthält und das Sie hier kostenlos herunterladen können .

Hier ist ein Artikel über BitFlex, wenn Sie weitere Informationen wünschen. Sie werden feststellen, dass wenn Sie nach Steuerelementen im Windows Explorer-Stil suchen, diese im Allgemeinen nie sofort verfügbar sind. Da WPF im Allgemeinen nicht mit Handles funktioniert, können Sie keinen einfachen Wrapper um Win32 oder ein vorhandenes Steuerelement schreiben, wie Sie es können mit WinForms.

Bildschirmfoto: Geben Sie hier die Bildbeschreibung ein


1
Wow, das sieht ein bisschen hackisch aus. Wie kann ich das tun, wenn ich ein Benutzersteuerelement mit XAML erstelle?
Louis Rhys

Das tust du nicht. So wird es gemacht. Wenn Sie dies kapseln möchten, erstellen Sie ein Benutzersteuerelement und eine CueText-Eigenschaft und rufen Sie SetCueText im Setter auf.
David Anderson

Ich denke, OP sollte Winforms-Steuerelemente hosten, um diesen Ansatz zu verwenden. Oder gibt es eine Möglichkeit, Textbox-Handles zu erhalten?
Standardgebietsschema

Dies scheint etwas zu sein, das mit WPF deklarativ durchgeführt werden könnte, indem gebunden wird, ob das Textfeld den Fokus hat oder nicht usw. - Das obige Beispiel ist eher ein WinForms-Ansatz - es funktioniert in WPF, ist aber nicht richtig Weg.
BrainSlugs83

1
Entschuldigung, aber diese Antwort ist einfach falsch. Auch alle Links sind kaputt.
Forest Kunecke
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.