Je cherche un moyen d'ajouter du texte de substitution dans une zone de texte, comme vous le pouvez avec une zone de texte au format HTML 5.
C'est à dire. si la zone de texte n'a pas de texte, il ajoute le texte Enter some text here
; lorsque l'utilisateur clique dessus, le texte de substitution est supprimé et permet à l'utilisateur de saisir son propre texte. Si la zone de texte perd le focus et qu'il n'y a toujours pas de texte, il est remplacé. ajouté à la zone de texte.
Ne serait-ce pas juste quelque chose comme ça:
Textbox myTxtbx = new Textbox();
myTxtbx.Text = "Enter text here...";
myTxtbx.GotFocus += GotFocus.EventHandle(RemoveText);
myTxtbx.LostFocus += LostFocus.EventHandle(AddText);
public void RemoveText(object sender, EventArgs e)
{
myTxtbx.Text = "";
}
public void AddText(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(myTxtbx.Text))
myTxtbx.Text = "Enter text here...";
}
C’est juste un pseudocode mais le concept est là.
Vous pouvez l'utiliser, c'est un travail pour moi et c'est une solution extrêmement simple.
<Style x:Key="placeHolder" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{Binding Path=Text,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
x:Name="textSource"
Background="Transparent"
Panel.ZIndex="2" />
<TextBox Text="{TemplateBinding Tag}" Background="{TemplateBinding Background}" Panel.ZIndex="1">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Text, Source={x:Reference textSource}}" Value="">
<Setter Property="Foreground" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Usage:
<TextBox Style="{StaticResource placeHolder}" Tag="Name of customer" Width="150" Height="24"/>
Au lieu de gérer les événements focus enter et focus leave afin de définir et de supprimer le texte fictif, il est possible d'utiliser la fonction Windows SendMessage pour envoyer un message EM_SETCUEBANNER
à notre zone de texte afin d'effectuer le travail pour nous.
Cela peut être fait en deux étapes faciles. Nous devons d’abord exposer la fonction SendMessage
de Windows.
private const int EM_SETCUEBANNER = 0x1501;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);
Ensuite, appelez simplement la méthode avec le descripteur de notre zone de texte, la valeur de EM_SETCUEBANNER et le texte que vous souhaitez définir.
SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "Username");
SendMessage(textBox2.Handle, EM_SETCUEBANNER, 0, "Password");
Référence: Définir le texte de substitution pour la zone de texte (texte de repère)
Ajoutez cette classe à votre projet et construisez votre solution. Cliquez sur Boîte à outils sur Visual Studio pour voir un nouveau composant de zone de texte appelé PlaceholderTextBox. Supprimez votre zone de texte actuelle lors de la création du formulaire et remplacez-la par PlaceHolderTextBox.
PlaceHolderTextBox a une propriété PlaceHolderText. Définissez le texte que vous voulez et passez une bonne journée :)
public class PlaceHolderTextBox : TextBox
{
bool isPlaceHolder = true;
string _placeHolderText;
public string PlaceHolderText
{
get { return _placeHolderText; }
set
{
_placeHolderText = value;
setPlaceholder();
}
}
public new string Text
{
get => isPlaceHolder ? string.Empty : base.Text;
set => base.Text = value;
}
//when the control loses focus, the placeholder is shown
private void setPlaceholder()
{
if (string.IsNullOrEmpty(base.Text))
{
base.Text = PlaceHolderText;
this.ForeColor = Color.Gray;
this.Font = new Font(this.Font, FontStyle.Italic);
isPlaceHolder = true;
}
}
//when the control is focused, the placeholder is removed
private void removePlaceHolder()
{
if (isPlaceHolder)
{
base.Text = "";
this.ForeColor = System.Drawing.SystemColors.WindowText;
this.Font = new Font(this.Font, FontStyle.Regular);
isPlaceHolder = false;
}
}
public PlaceHolderTextBox()
{
GotFocus += removePlaceHolder;
LostFocus += setPlaceholder;
}
private void setPlaceholder(object sender, EventArgs e)
{
setPlaceholder();
}
private void removePlaceHolder(object sender, EventArgs e)
{
removePlaceHolder();
}
}
Ce n'est pas mon code, mais je l'utilise beaucoup et cela fonctionne parfaitement ... XAML SEULEMENT
<TextBox x:Name="Textbox" Height="23" Margin="0,17,18.8,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" HorizontalAlignment="Right" ></TextBox>
<TextBlock x:Name="Placeholder" IsHitTestVisible="False" TextWrapping="Wrap" Text="Placeholder Text" VerticalAlignment="Top" Margin="0,20,298.8,0" Foreground="DarkGray" HorizontalAlignment="Right" Width="214">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=Textbox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Les propriétés attachées à la rescousse:
public static class TextboxExtensions
{
public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
"Placeholder", typeof(string), typeof(TextboxExtensions), new PropertyMetadata(default(string), propertyChangedCallback: PlaceholderChanged));
private static void PlaceholderChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var tb = dependencyObject as TextBox;
if(tb == null)
return;
tb.LostFocus -= OnLostFocus;
tb.GotFocus -= OnGotFocus;
if (args.NewValue != null)
{
tb.GotFocus += OnGotFocus;
tb.LostFocus += OnLostFocus;
}
}
private static void OnLostFocus(object sender, RoutedEventArgs routedEventArgs)
{
var tb = sender as TextBox;
if (string.IsNullOrEmpty(tb.Text) || string.IsNullOrWhiteSpace(tb.Text))
{
tb.Text = GetPlaceholder(tb);
}
}
private static void OnGotFocus(object sender, RoutedEventArgs routedEventArgs)
{
var tb = sender as TextBox;
var ph = GetPlaceholder(tb);
if (tb.Text == ph)
{
tb.Text = string.Empty;
}
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static void SetPlaceholder(DependencyObject element, string value)
{
element.SetValue(PlaceholderProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static string GetPlaceholder(DependencyObject element)
{
return (string) element.GetValue(PlaceholderProperty);
}
}
Usage:
<TextBox Text="hi" local:TextboxExtensions.Placeholder="Hello there"></TextBox>
Bien que l’utilisation du message EM_SETCUEBANNER
soit probablement la plus simple, il ya une chose que je n’aime pas, c’est que le texte de substitution disparaisse lorsque le contrôle obtient le focus. C'est ma bête noire lorsque je remplis des formulaires. Je dois cliquer dessus pour me rappeler à quoi sert le champ.
Voici donc une autre solution pour WinForms. Il recouvre une Label
au-dessus du contrôle, qui ne disparaît que lorsque l'utilisateur commence à taper.
Ce n'est certainement pas à l'épreuve des balles. Il accepte toutes les variables Control
, mais je l’ai testé uniquement avec une variable TextBox
. Des modifications peuvent être nécessaires pour fonctionner avec certains contrôles. La méthode retourne le contrôle Label
au cas où vous auriez besoin de le modifier un peu dans un cas spécifique, mais cela ne sera peut-être jamais nécessaire.
Utilisez-le comme ceci:
SetPlaceholder(txtSearch, "Type what you're searching for");
Voici la méthode:
/// <summary>
/// Sets placeholder text on a control (may not work for some controls)
/// </summary>
/// <param name="control">The control to set the placeholder on</param>
/// <param name="text">The text to display as the placeholder</param>
/// <returns>The newly-created placeholder Label</returns>
public static Label SetPlaceholder(Control control, string text) {
var placeholder = new Label {
Text = text,
Font = control.Font,
ForeColor = Color.Gray,
BackColor = Color.Transparent,
Cursor = Cursors.IBeam,
Margin = Padding.Empty,
//get rid of the left margin that all labels have
FlatStyle = FlatStyle.System,
AutoSize = false,
//Leave 1px on the left so we can see the blinking cursor
Size = new Size(control.Size.Width - 1, control.Size.Height),
Location = new Point(control.Location.X + 1, control.Location.Y)
};
//when clicking on the label, pass focus to the control
placeholder.Click += (sender, args) => { control.Focus(); };
//disappear when the user starts typing
control.TextChanged += (sender, args) => {
placeholder.Visible = string.IsNullOrEmpty(control.Text);
};
//stay the same size/location as the control
EventHandler updateSize = (sender, args) => {
placeholder.Location = new Point(control.Location.X + 1, control.Location.Y);
placeholder.Size = new Size(control.Size.Width - 1, control.Size.Height);
};
control.SizeChanged += updateSize;
control.LocationChanged += updateSize;
control.Parent.Controls.Add(placeholder);
placeholder.BringToFront();
return placeholder;
}
Vous pouvez obtenir la valeur par défaut Template
, modifiez-la en superposant une TextBlock
et utilisez une Style
pour ajouter des déclencheurs qui la masquent et l'afficher dans les états appropriés.
Basé sur la réponse d'ExceptionLimeCat, une amélioration:
Color farbe;
string ph = "Placeholder-Text";
private void Form1_Load(object sender, EventArgs e)
{
farbe = myTxtbx.ForeColor;
myTxtbx.GotFocus += RemoveText;
myTxtbx.LostFocus += AddText;
myTxtbx.Text = ph;
}
public void RemoveText(object sender, EventArgs e)
{
myTxtbx.ForeColor = farbe;
if (myTxtbx.Text == ph)
myTxtbx.Text = "";
}
public void AddText(object sender, EventArgs e)
{
if (String.IsNullOrWhiteSpace(myTxtbx.Text))
{
myTxtbx.ForeColor = Color.Gray;
myTxtbx.Text = ph;
}
}
Cela voudrait dire que vous avez un bouton qui vous permet de faire une action, telle que la connexion ou autre chose. Avant de faire l’action, vous vérifiez si la zone de texte est renseignée. Sinon, elle remplacera le texte.
private void button_Click(object sender, EventArgs e)
{
string textBoxText = textBox.Text;
if (String.IsNullOrWhiteSpace(textBoxText))
{
textBox.Text = "Fill in the textbox";
}
}
private void textBox_Enter(object sender, EventArgs e)
{
TextBox currentTextbox = sender as TextBox;
if (currentTextbox.Text == "Fill in the textbox")
{
currentTextbox.Text = "";
}
}
C'est un peu ringard, mais vérifier le texte pour le rapport qualité-prix que vous lui donnez est le meilleur que je puisse faire, mais pas aussi bon en C # pour obtenir une meilleure solution.
J'ai écrit un contrôle personnalisé réutilisable. Peut-être pourrait-il aider quelqu'un qui doit implémenter plusieurs zones de texte réservées dans son projet.
Voici la classe personnalisée avec l'exemple d'implémentation d'une instance, vous pouvez tester facilement en collant ce code sur un nouveau projet winforms à l'aide de VS:
namespace reusebleplaceholdertextbox
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// implementation
CustomPlaceHolderTextbox myCustomTxt = new CustomPlaceHolderTextbox(
"Please Write Text Here...", Color.Gray, new Font("ARIAL", 11, FontStyle.Italic)
, Color.Black, new Font("ARIAL", 11, FontStyle.Regular)
);
myCustomTxt.Multiline = true;
myCustomTxt.Size = new Size(200, 50);
myCustomTxt.Location = new Point(10, 10);
this.Controls.Add(myCustomTxt);
}
}
class CustomPlaceHolderTextbox : System.Windows.Forms.TextBox
{
public string PlaceholderText { get; private set; }
public Color PlaceholderForeColor { get; private set; }
public Font PlaceholderFont { get; private set; }
public Color TextForeColor { get; private set; }
public Font TextFont { get; private set; }
public CustomPlaceHolderTextbox(string placeholdertext, Color placeholderforecolor,
Font placeholderfont, Color textforecolor, Font textfont)
{
this.PlaceholderText = placeholdertext;
this.PlaceholderFont = placeholderfont;
this.PlaceholderForeColor = placeholderforecolor;
this.PlaceholderFont = placeholderfont;
this.TextForeColor = textforecolor;
this.TextFont = textfont;
if (!string.IsNullOrEmpty(this.PlaceholderText))
{
SetPlaceHolder(true);
this.Update();
}
}
private void SetPlaceHolder(bool addEvents)
{
if (addEvents)
{
this.LostFocus += txt_lostfocus;
this.Click += txt_click;
}
this.Text = PlaceholderText;
this.ForeColor = PlaceholderForeColor;
this.Font = PlaceholderFont;
}
private void txt_click(object sender, EventArgs e)
{
// IsNotFirstClickOnThis:
// if there is no other control in the form
// we will have a problem after the first load
// because we dont other focusable control to move the focus to
// and we dont want to remove the place holder
// only on first time the place holder will be removed by click event
RemovePlaceHolder();
this.GotFocus += txt_focus;
// no need for this event listener now
this.Click -= txt_click;
}
private void RemovePlaceHolder()
{
this.Text = "";
this.ForeColor = TextForeColor;
this.Font = TextFont;
}
private void txt_lostfocus(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(this.Text))
{
// set placeholder again
SetPlaceHolder(false);
}
}
private void txt_focus(object sender, EventArgs e)
{
if (this.Text == PlaceholderText)
{
// IsNotFirstClickOnThis:
// if there is no other control in the form
// we will have a problem after the first load
// because we dont other focusable control to move the focus to
// and we dont want to remove the place holder
RemovePlaceHolder();
}
}
}
}
J'ai mis au point une méthode qui a fonctionné pour moi, mais uniquement parce que j'étais disposé à utiliser le nom de la zone de texte comme espace réservé. Voir ci-dessous.
public TextBox employee = new TextBox();
private void InitializeHomeComponent()
{
//
//employee
//
this.employee.Name = "Caller Name";
this.employee.Text = "Caller Name";
this.employee.BackColor = System.Drawing.SystemColors.InactiveBorder;
this.employee.Location = new System.Drawing.Point(5, 160);
this.employee.Size = new System.Drawing.Size(190, 30);
this.employee.TabStop = false;
this.Controls.Add(employee);
// I loop through all of my textboxes giving them the same function
foreach (Control C in this.Controls)
{
if (C.GetType() == typeof(System.Windows.Forms.TextBox))
{
C.GotFocus += g_GotFocus;
C.LostFocus += g_LostFocus;
}
}
}
private void g_GotFocus(object sender, EventArgs e)
{
var tbox = sender as TextBox;
tbox.Text = "";
}
private void g_LostFocus(object sender, EventArgs e)
{
var tbox = sender as TextBox;
if (tbox.Text == "")
{
tbox.Text = tbox.Name;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace App_name
{
public class CustomTextBox : TextBox
{
private string Text_ = "";
public CustomTextBox() : base()
{}
public string setHint
{
get { return Text_; }
set { Text_ = value; }
}
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
if (Text_.Equals(this.Text))
this.Clear();
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
if (String.IsNullOrWhiteSpace(this.Text))
this.Text = Text_;
}
}
}
> xmlns:local="clr-namespace:app_name"
> <local:CustomTextBox
> x:Name="id_number_txt"
> Width="240px"
> Height="auto"/>
Je viens ici avec cette solution inspirée par @Kemal Karadag.
J'ai remarqué que chaque solution publiée ici repose sur le focus,
Alors que je voulais que mon espace réservé soit le clone exact d'un espace réservé HTML standard dans Google Chrome.
Au lieu de masquer/afficher l’espace réservé lorsque la boîte est centrée,
Je cache/affiche l'espace réservé en fonction de la longueur du texte de la boîte:
Si la boîte est vide, l'espace réservé est affiché et si vous tapez dans la zone, l'espace réservé disparaît.
Comme il est hérité d'une TextBox standard, vous pouvez le trouver dans votre Boîte à outils!
using System;
using System.Drawing;
using System.Windows.Forms;
public class PlaceHolderTextBox : TextBox
{
private bool isPlaceHolder = true;
private string placeHolderText;
public string PlaceHolderText
{
get { return placeHolderText; }
set
{
placeHolderText = value;
SetPlaceholder();
}
}
public PlaceHolderTextBox()
{
TextChanged += OnTextChanged;
}
private void SetPlaceholder()
{
if (!isPlaceHolder)
{
this.Text = placeHolderText;
this.ForeColor = Color.Gray;
isPlaceHolder = true;
}
}
private void RemovePlaceHolder()
{
if (isPlaceHolder)
{
this.Text = this.Text[0].ToString(); // Remove placeHolder text, but keep the character we just entered
this.Select(1, 0); // Place the caret after the character we just entered
this.ForeColor = System.Drawing.SystemColors.WindowText;
isPlaceHolder = false;
}
}
private void OnTextChanged(object sender, EventArgs e)
{
if (this.Text.Length == 0)
{
SetPlaceholder();
}
else
{
RemovePlaceHolder();
}
}
}
vous pouvez également le faire lorsque la souris clique, supposons que votre texte fictif soit "User_Name"
private void textBox1_MouseClick(object sender, MouseEventArgs e)
{
if(textBox1.Text == "User_Name")
textBox1.Text = "";
}
Au lieu d'utiliser la propriété .Text d'un TextBox, j'ai recouvert un TextBlock avec l'espace réservé . Je ne pouvais pas utiliser la propriété .Text car elle était liée à un événement.
XAML:
<Canvas Name="placeHolderCanvas">
<TextBox AcceptsReturn="True" Name="txtAddress" Height="50" Width="{Binding ActualWidth, ElementName=placeHolderCanvas}"
Tag="Please enter your address"/>
</Canvas>
VB.NET
Public Shared Sub InitPlaceholder(canvas As Canvas)
Dim txt As TextBox = canvas.Children.OfType(Of TextBox).First()
Dim placeHolderLabel = New TextBlock() With {.Text = txt.Tag,
.Foreground = New SolidColorBrush(Color.FromRgb(&H77, &H77, &H77)),
.IsHitTestVisible = False}
Canvas.SetLeft(placeHolderLabel, 3)
Canvas.SetTop(placeHolderLabel, 1)
canvas.Children.Add(placeHolderLabel)
AddHandler txt.TextChanged, Sub() placeHolderLabel.Visibility = If(txt.Text = "", Visibility.Visible, Visibility.Hidden)
End Sub
il existe de MEILLEURES solutions, mais la solution la plus simple est la suivante:
Fonctionne comme un charme.
public class WTextBox : TextBox
{
private string _placeholder;
[Category("Appearance")]
public string Placeholder
{
get { return _placeholder; }
set
{
_placeholder = value ?? string.Empty;
Invalidate();
}
}
public WTextBox()
{
_placeholder = string.Empty;
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg != 0xF || Focused || !string.IsNullOrEmpty(Text) || string.IsNullOrWhiteSpace(_placeholder))
{
return;
}
using (var g = CreateGraphics())
{
TextRenderer.DrawText(g, _placeholder, Font, ClientRectangle, SystemColors.GrayText, BackColor, TextFormatFlags.Left);
}
}
}
public void Initialize()
{
SetPlaceHolder(loginTextBox, " Логин ");
SetPlaceHolder(passwordTextBox, " Пароль ");
}
public void SetPlaceHolder(Control control, string PlaceHolderText)
{
control.Text = PlaceHolderText;
control.GotFocus += delegate(object sender, EventArgs args) {
if (control.Text == PlaceHolderText)
{
control.Text = "";
}
};
control.LostFocus += delegate(object sender, EventArgs args){
if (control.Text.Length == 0)
{
control.Text = PlaceHolderText;
}
};
}
Vous pouvez aussi essayer de cette façon ..
appeler la fonction
TextboxPlaceHolder(this.textBox1, "YourPlaceHolder");
écrire cette fonction
private void TextboxPlaceHolder(Control control, string PlaceHolderText)
{
control.Text = PlaceHolderText;
control.GotFocus += delegate (object sender, EventArgs args)
{
if (cusmode == false)
{
control.Text = control.Text == PlaceHolderText ? string.Empty : control.Text;
//IF Focus TextBox forecolor Black
control.ForeColor = Color.Black;
}
};
control.LostFocus += delegate (object sender, EventArgs args)
{
if (string.IsNullOrWhiteSpace(control.Text) == true)
{
control.Text = PlaceHolderText;
//If not focus TextBox forecolor to gray
control.ForeColor = Color.Gray;
}
};
}
Essayez le code suivant:
<TextBox x:Name="InvoiceDate" Text="" Width="300" TextAlignment="Left" Height="30" Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" />
<TextBlock IsHitTestVisible="False" Text="Men att läsa" Width="300" TextAlignment="Left" Height="30" Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="2" Padding="5, 5, 5, 5" Foreground="LightGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=InvoiceDate}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=InvoiceDate, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>