Jak mogę dodać tekst podpowiedzi do pola tekstowego WPF?

107

Na przykład Facebook ma tekst wskazówki „Szukaj” w polu tekstowym Szukaj, gdy pole tekstowe jest puste.

Jak to osiągnąć dzięki polom tekstowym WPF?

Pole tekstowe wyszukiwania Facebooka

Louis Rhys
źródło
2
Spróbuj wyszukać „cue banner”.
domyślne ustawienia regionalne
@MAKKAM ten artykuł MSDN omawia to, ale nie pokazuje, jak to się robi
Louis Rhys
1
Nie nazwałbym tego, o co prosisz, „tekstem podpowiedzi”. dla mnie tekst podpowiedzi to wyskakujące okienko. niemniej jednak znalazłem to pytanie, gdy chciałem ustawić tekst zastępczy. a poniższe odpowiedzi pomogły mi.
steve
1
Nawiasem

Odpowiedzi:

158

Możesz to osiągnąć znacznie łatwiej za pomocą a VisualBrushi niektórych wyzwalaczy w 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>

Aby zwiększyć możliwość ponownego Styleużycia, możesz również utworzyć zestaw dołączonych właściwości, aby kontrolować rzeczywisty tekst, kolor, orientację itp.

sellmeadog
źródło
1
Użyj IsMouseCaptured zamiast IsKeyboardFocused. Tak reaguje prawdziwy baner podpowiedzi.
Monstieur
5
Jeśli ktoś zastanawiał się, jak użyć dołączonych właściwości, aby zwiększyć możliwość ponownego użycia stylu, zobacz: stackoverflow.com/a/650620/724944
surfen
@Kurian IsMouseCaptured spowoduje, że pamięć zniknie tylko wtedy, gdy klikniesz ją myszą, ale pojawi się ponownie po zwolnieniu przycisku myszy. To nie wygląda dobrze. IsMouseOver też nie byłby dobry (klawiatura ma fokus, ale wskaźnik myszy jest gdzie indziej => wyświetlana cue). Większość banerów cue używa IsKeyboardFocused (na przykład Facebook) i myślę, że jest w porządku. Alternatywnym rozwiązaniem byłoby użycie obu wyzwalaczy: (IsMouseOver LUB IsKeyboardFocused)
surfowanie
23
Rozwiązaniem powinno być Hint = "Wprowadź tekst", a nie 20 elementów ... Niestety, nie jest to obsługiwane przez legendarne wbudowane pole tekstowe ...
Mzn
8
Chociaż takie podejście może być dobre w przypadku warunków domyślnych, nie działa, gdy pole tekstowe zawiera już pędzel tła lub tło formularza nie jest tego samego koloru, co pole tekstowe.
LWChris
56

To jest moje proste rozwiązanie, zaadaptowane od firmy 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>
Martin Schmidt
źródło
Ciekawe podejście Nie pomyślałbym od razu o sobie.
itsmatt
ładne i proste :)
shmulik.r
3
To rozwiązanie działa szczególnie dobrze, jeśli ustawisz TextBlock naIsHitTestVisible="False"
Mage Xy,
1
@MageXy odnosi się do pierwszego TextBlocka (podpowiedzi).
Felix,
To rozwiązanie działa świetnie, jeśli chcesz powiązać tekst podpowiedzi z właściwością.
PeterB
11

co z korzystaniem z materialDesign HintAssist? Używam tego, który również możesz dodać pływającą wskazówkę:

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

Zainstalowałem Material Design z pakietem Nuget. W linku do dokumentacji znajduje się instrukcja instalacji

Mahdi Khalili
źródło
2
Bardzo przydatna biblioteka
AlexF11,
9

Zrób to w kodzie, ustawiając początkowo kolor tekstu na szary i dodając programy obsługi zdarzeń w celu uzyskania i utraty fokusu klawiatury.

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

Następnie programy obsługi zdarzeń:

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";
        }
    }
}
mxgg250
źródło
7
-1 za zrobienie tego w kodzie za: zaśmieca sterowanie i istnieje duże prawdopodobieństwo, że będzie to kolidować z inną logiką sterowania, jeśli nie teraz, to w przyszłości.
AlexeiOst
4

Możesz to zrobić w bardzo prosty sposób. Pomysł polega na umieszczeniu etykiety w tym samym miejscu, w którym znajduje się pole tekstowe. Twoja etykieta będzie widoczna, jeśli pole tekstowe nie zawiera tekstu i nie jest fokusem.

 <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: jeśli chcesz mieć domyślną wartość dla swojego textBox, pamiętaj, aby ustawić ją później podczas przesyłania danych (na przykład: „InputText” = „PlaceHolder Text Here”, jeśli jest puste).

makertoo
źródło
2

Inne podejście ;-)

działa to również z PasswordBox. Jeśli chcesz go używać TextBox, po prostu zamień go PasswordChangedz 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;
    }
}
Mata
źródło
Najlepsze i najprostsze rozwiązanie jakie znalazłem !! Dzięki!!
steve
2

Kiedyś znalazłem się w tej samej sytuacji, rozwiązałem to w następujący sposób. Spełniłem tylko wymagania pola podpowiedzi, możesz uczynić go bardziej interaktywnym, dodając efekty i inne rzeczy do innych wydarzeń, takich jak skupienie itp.

KOD WPF (usunąłem style, aby były czytelne)

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

Kod 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;
        }
    }
Mohammad Mahroz
źródło
1

Innym rozwiązaniem jest użycie zestawu narzędzi WPF, takiego jak MahApps.Metro. Ma wiele fajnych funkcji, takich jak znak wodny w polu tekstowym:

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

Zobacz http://mahapps.com/controls/textbox.html

StefanG
źródło
0

Wykorzystałem zdarzenia „get and lost focus”:

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

Działa dobrze, ale tekst jest nadal szary. Potrzebuje posprzątania. Używałem VB.NET

StarLordBlair
źródło
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>
DerBesondereEin
źródło
0

To moja opinia:

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

Moim zdaniem większość innych odpowiedzi, w tym pierwsza, ma wady.

To rozwiązanie działa w każdych okolicznościach. Czysty XAML, łatwy do ponownego użycia.

juliański
źródło
-1

I to osiągnąć z VisualBrusha niektóre wyzwalacze w A Stylesugerowane przez: 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: aplikacja działa, projekt bt nie ładuje się ... pojawia się następujący błąd: Niejednoznaczne odwołanie do typu. Typ o nazwie „StaticExtension” występuje w co najmniej dwóch przestrzeniach nazw: „MS.Internal.Metadata.ExposedTypes.Xaml” i „System.Windows.Markup”. Rozważ dostosowanie atrybutów XmlnsDefinition zestawu. Używam .net 3.5

SUHAIL AG
źródło
Rozwiązano problem, zmieniając <Trigger Property="Text" Value="{x:Static sys:String.Empty}">na<Trigger Property="Text" Value="">
SUHAIL AG
6
Wygląda na to, że jest to odpowiedź na inny post. Jako odpowiedzi prosimy zamieszczać tylko kompletne rozwiązania pytania.
Drew Gaynor,
4
Jeśli uważasz, że odpowiedź @ sellmeadog jest prawie poprawna, rozważ jej poprawienie, zamiast publikować nową, prawie bez różnicy.
0xBADF00D
-11

W przypadku WPF nie ma sposobu. Musisz to naśladować. Zobacz ten przykład . Pomocniczym (niestabilnym rozwiązaniem) jest hostowanie kontrolki użytkownika WinForms, która dziedziczy z TextBox i wysyłanie komunikatu EM_SETCUEBANNER do kontrolki edycji. to znaczy.

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

Ponadto, jeśli chcesz hostować podejście kontrolne WinForm, mam strukturę, która już zawiera tę implementację o nazwie BitFlex Framework, którą możesz pobrać bezpłatnie tutaj .

Tutaj jest artykuł o BitFlex, jeśli chcesz uzyskać więcej informacji. Zaczniesz odkrywać, że jeśli chcesz mieć elementy sterujące w stylu Eksploratora Windows, które zwykle nigdy nie wychodzą z pudełka, a ponieważ WPF nie działa z uchwytami, generalnie nie możesz napisać łatwego otoki wokół Win32 lub istniejącej kontrolki, tak jak możesz z WinForms.

Zrzut ekranu: wprowadź opis obrazu tutaj

David Anderson
źródło
1
wow, to wygląda trochę hakersko. Jak mogę to zrobić podczas tworzenia kontrolki użytkownika za pomocą XAML?
Louis Rhys,
Ty nie. Tak to się robi. Jeśli chcesz to hermetyzować, utwórz kontrolkę użytkownika i właściwość CueText i wywołaj SetCueText w metodzie ustawiającej.
David Anderson,
Wydaje mi się, że OP powinien obsługiwać kontrolki WinForms, aby zastosować to podejście. Czy jest sposób, aby uzyskać uchwyt pola tekstowego?
domyślne ustawienia regionalne
Wydaje się, że jest to coś, co można zrobić deklaratywnie z WPF, wiążąc się z tym, czy pole tekstowe ma fokus, czy nie, itp. - Powyższy przykład jest bardziej podejściem WinForms - będzie działać w WPF, ale nie jest to właściwe sposób.
BrainSlugs83
2
Przepraszamy, ale ta odpowiedź jest po prostu nieprawidłowa. Również wszystkie linki są uszkodzone.
Forest Kunecke