Par exemple, Facebook a un texte d'indication «Rechercher» dans la zone de texte Rechercher lorsque la zone de texte est vide.
Comment y parvenir avec les zones de texte WPF?
Par exemple, Facebook a un texte d'indication «Rechercher» dans la zone de texte Rechercher lorsque la zone de texte est vide.
Comment y parvenir avec les zones de texte WPF?
Réponses:
Vous pouvez accomplir cela beaucoup plus facilement avec a VisualBrush
et certains déclencheurs dans 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>
Pour augmenter la réutilisabilité de cela Style
, vous pouvez également créer un ensemble de propriétés attachées pour contrôler le texte, la couleur, l'orientation, etc. de la bannière de repère.
C'est ma solution simple, adaptée de 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>
IsHitTestVisible="False"
qu'en est-il de l'utilisation de materialDesign HintAssist? J'utilise ceci et vous pouvez également ajouter un indice flottant:
<TextBox Width="150" Height="40" Text="hello" materialDesign:HintAssist.Hint="address" materialDesign:HintAssist.IsFloating="True"></TextBox>
J'ai installé Material Design avec Nuget Package il y a un guide d'installation dans le lien de documentation
Faites-le dans le code-behind en définissant initialement la couleur du texte sur gris et en ajoutant des gestionnaires d'événements pour gagner et perdre le focus clavier.
TextBox tb = new TextBox();
tb.Foreground = Brushes.Gray;
tb.Text = "Text";
tb.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_GotKeyboardFocus);
tb.LostKeyboardFocus += new KeyboardFocusChangedEventHandler(tb_LostKeyboardFocus);
Puis les gestionnaires d'événements:
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";
}
}
}
Vous devez créer un contrôle personnalisé en héritant de la zone de texte. Le lien ci-dessous présente un excellent exemple de l'exemple de zone de texte de recherche. Veuillez jeter un œil à ceci
http://davidowens.wordpress.com/2009/02/18/wpf-search-text-box/
Vous pouvez le faire d'une manière très simple. L'idée est de placer une étiquette au même endroit que votre zone de texte. Votre étiquette sera visible si la zone de texte n'a pas de texte et n'a pas le 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: Si vous voulez avoir une valeur par défaut pour votre textBox, assurez-vous de la définir après la soumission des données (par exemple: "InputText" = "PlaceHolder Text Here" si vide).
Une autre approche ;-)
cela fonctionne également avec PasswordBox
. Si vous souhaitez l'utiliser avec TextBox
, échangez simplement PasswordChanged
avec 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;
}
}
Une fois, je me suis retrouvé dans la même situation, je l'ai résolu de la manière suivante. J'ai seulement rempli les conditions d'une boîte d'indices, vous pouvez la rendre plus interactive en ajoutant des effets et d'autres choses sur d'autres événements comme la mise au point, etc.
CODE WPF (j'ai supprimé le style pour le rendre lisible)
<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>
Code 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;
}
}
Une autre solution consiste à utiliser une boîte à outils WPF comme MahApps.Metro. Il a de nombreuses fonctionnalités intéressantes, comme un filigrane de zone de texte:
Controls:TextBoxHelper.Watermark="Search..."
J'ai utilisé les événements de focus obtenu et perdu:
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
Cela fonctionne bien, mais le texte est toujours en gris. Besoin de nettoyage. J'utilisais VB.NET
<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>
C'est mon avis:
<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 plupart des autres réponses, y compris la première, ont des défauts à mon avis.
Cette solution fonctionne en toutes circonstances. Pure XAML, facilement réutilisable.
Je réalise cela avec un VisualBrush
et certains déclencheurs dans une Style
Suggérée par: 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: Application en cours d'exécution, bt Design ne se chargeant pas ... l'erreur suivante vient: Référence de type ambiguë. Un type nommé «StaticExtension» apparaît dans au moins deux espaces de noms, «MS.Internal.Metadata.ExposedTypes.Xaml» et «System.Windows.Markup». Envisagez d'ajuster les attributs XmlnsDefinition de l'assembly. J'utilise .net 3.5
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
à<Trigger Property="Text" Value="">
Pour WPF, il n'y a pas de moyen. Vous devez l'imiter. Voyez cet exemple . Une solution secondaire (floconneuse) consiste à héberger un contrôle utilisateur WinForms qui hérite de TextBox et à envoyer le message EM_SETCUEBANNER au contrôle d'édition. c'est à 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);
}
De plus, si vous souhaitez héberger une approche de contrôle WinForm, j'ai un framework qui inclut déjà cette implémentation appelée BitFlex Framework, que vous pouvez télécharger gratuitement ici .
Voici un article sur BitFlex si vous souhaitez plus d'informations. Vous commencerez à constater que si vous cherchez à avoir des contrôles de style Explorateur Windows, cela ne sort généralement jamais de la boîte, et parce que WPF ne fonctionne pas avec des poignées généralement, vous ne pouvez pas écrire un wrapper facile autour de Win32 ou un contrôle existant comme vous pouvez avec WinForms.
Capture d'écran: