183

I am looking for a way to add placeholder text to a textbox like you can with a textbox in html5.

I.e. if the textbox has no text, then it adds the text Enter some text here, when the user clicks on it the placeholder text disappears and allows the user to enter their own text, and if the textbox loses focus and there is still no text then the placeholder is added back to the textbox.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Boardy
  • 35,417
  • 104
  • 256
  • 447
  • 5
    Don't use Text property for placeholder text. It will interfere with the binding. Use AdornerDecorator (http://msdn.microsoft.com/en-us/library/system.windows.documents.adornerdecorator(v=vs.110).aspx) – Pavel Voronin Mar 14 '14 at 12:57
  • 2
    Take a look at http://stackoverflow.com/questions/833943/watermark-hint-text-placeholder-textbox-in-wpf – SepehrM Aug 08 '14 at 16:25
  • 6
    Just an FYI - *Watermark* aka *hint text* aka *placeholder text* aka *cue banner*. All these terms have synonymous intention. – RBT Jun 16 '18 at 02:35
  • [Watermark TextBox in WinForms](https://stackoverflow.com/a/36534068/3110834) – Reza Aghaei Dec 02 '19 at 11:03
  • Does this answer your question? [Watermark / hint text / placeholder TextBox](https://stackoverflow.com/questions/833943/watermark-hint-text-placeholder-textbox) – StayOnTarget Jun 24 '21 at 12:28
  • Visual Studio 2019 supports placeholder text on textboxes right out of the box. – BuddyRoach Dec 08 '21 at 07:08

27 Answers27

121

Wouldn't that just be something like this:

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)
{
    if (myTxtbx.Text == "Enter text here...") 
    {
     myTxtbx.Text = "";
    }
}

public void AddText(object sender, EventArgs e)
{
    if (string.IsNullOrWhiteSpace(myTxtbx.Text))
        myTxtbx.Text = "Enter text here...";
}

Thats just pseudocode but the concept is there.

ExceptionLimeCat
  • 6,191
  • 6
  • 44
  • 77
  • 2
    Thanks I was expecting there to be some sort of XAML that can be used to create the placeholder. Thanks for your help – Boardy Aug 08 '12 at 22:07
  • 1
    I was hoping to find a solution that would keep the placeholder text in the textbox until the user entered text. Seems like that would work better. – DROP TABLE users Dec 20 '13 at 22:49
  • 11
    This will work BUT if textbox value is bound to source then you probably have a problem. – Pavel Voronin Mar 14 '14 at 12:53
  • 1
    This is good simple solution, only thing is that even after entering text, if user again clicks on the textbox (eg to append more text or delete some characters) the whole textbox will lose the entered value – Bibaswann Bandyopadhyay Jun 15 '15 at 18:45
  • 3
    `RemoveText` and `AddText` method should be `public void`, missing **void**. And as @BibaswannBandyopadhyay has said, the `RemoveText` method could be this: `if (myTxtbx.Text == "Enter text here...") {myTxtbx.Text = "";}` – KaKa Jun 17 '16 at 12:57
  • Looks like Microsoft addressed this in their next framework after WPF; UWP has a PlaceholderText property on TextBox (which of course isn't helpful but I found it interesting) – gusmally supports Monica Jul 31 '19 at 18:51
  • This will not work if the textbox also has `TextChanged` event handler – newbieguy Dec 07 '19 at 11:59
107

You can use this, it's working for me and is extremely simple solution.

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

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

MacGile
  • 1,239
  • 1
  • 9
  • 9
  • 1
    Hi @MacGile, i modified your great solution, because i need the two way binding between the original text property and textSource.Text property. – Gábor Plesz Mar 05 '14 at 11:44
  • 1
    @Rob put it in a resource dictionary. Window.Resources, etc. – Brian Nov 03 '14 at 22:10
  • This is fantastic! Question, this causes the textboxes with this style to hold onto focus 3 times. Is there a way to allow normal focus traversal using this style? – Joe Bauer Jan 09 '15 at 20:30
  • 9
    For focus issues add this : ` ` – Cihan Yakar Jun 05 '15 at 08:00
  • When tabbing into the control, the placeholder doesn't disappear, and the text is added before the placeholder text. – Ziv Sep 17 '15 at 15:29
  • 1
    I'd tack on `TextWrapping="wrap"` onto both of the TextBox tags in the Style, in case you want to do a multi-line TextBox with Placeholder text like I did. – jpcguy89 Nov 04 '15 at 17:43
  • Textbox does not accept return after adding this style.. why so? any solution? – Sachin Jan 04 '16 at 11:21
  • I do the same with [this ValueConverter](https://gist.github.com/JonasDralle/644196a273d41140555a) – BlueWizard Feb 03 '16 at 19:19
  • Placed your XAML within my Application.Resources, because it shall be shared among all views. But even with the addition for focus issues, a XamlParseException with the inner exception "Cannot find resource named 'textPlaceHolder'. Resource names are case sensitive" is thrown. However, that's exactly the resource's name and both, IntelliSense and the XAML designer work correctly with that?! Placing it within Window.Resources, the exception is gone, but no placeholder text is shown, though. :( – Yoda Sep 15 '16 at 14:15
  • 1
    this does also break the maxLenght option – ColmanJ Nov 08 '16 at 08:57
  • 1
    @Sachin I've fixed my MaxLenght property. The problem is that one textbox is replaced with 2 textboxes. One for input and one for the placeholder. To fix broken properties you just need to add them to the first textbox like this: ``. In your case you probably need to add `AcceptsReturn="{TemplateBinding AcceptsReturn}"` – ColmanJ Nov 08 '16 at 09:14
  • 1
    @CihanYakar thank you! A little late but you saved me the day! This trick works amazing – Filippo Agostini Sep 06 '18 at 09:00
  • @FilippoAgostini :) always – Cihan Yakar Sep 12 '18 at 07:29
  • 2
    yeah, **extremely** simple ... : ^ – T.Todua Nov 05 '20 at 19:31
  • For some reason I cannot get this to work, I am wondering if it has to do with me theming my app. – DmVinny Feb 28 '21 at 19:10
58

Instead of handling the focus enter and focus leave events in order to set and remove the placeholder text it is possible to use the Windows SendMessage function to send EM_SETCUEBANNER message to our textbox to do the work for us.

This can be done with two easy steps. First we need to expose the Windows SendMessage function.

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

Then simply call the method with the handle of our textbox, EM_SETCUEBANNER’s value and the text we want to set.

SendMessage(textBox1.Handle, EM_SETCUEBANNER, 0, "Username");
SendMessage(textBox2.Handle, EM_SETCUEBANNER, 0, "Password");

Reference: Set placeholder text for textbox (cue text)

Abdullah Qudeer
  • 949
  • 7
  • 24
  • 12
    Note: this **does not work for WPF**. See: http://stackoverflow.com/questions/5054872/system-windows-controls-textbox-handle – ArtOfCode Jun 28 '16 at 19:17
  • 2
    Best answer here, but **note** Form_Load is too early, I had to wait until Form_Shown before it worked. – Jay Croghan Aug 24 '16 at 13:34
  • The only thing I hate about this is that the text disappears as soon as the control gets focus, which means if you didn't catch what it said (and it's important), you have to click off of it to see the placeholder text again. I added another answer to add a placeholder that disappears only after the user starts typing. – Gabriel Luci Dec 12 '16 at 17:07
  • Hello guys this doesn't work...Nothing happens... I am using winforms whyy!! – Meric Ozcan Jan 07 '23 at 21:08
32

Add this class your project and build your solution. Click to Toolbox on visual studio you will see a new textbox component named PlaceholderTextBox. Delete your current textbox on form designe and replace with PlaceHolderTextBox.

enter image description here

PlaceHolderTextBox has a property PlaceHolderText. Set any text you want and have nice day :)

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();
    }
}
Pepernoot
  • 3,409
  • 3
  • 21
  • 46
Kemal Karadag
  • 446
  • 4
  • 4
  • 14
    When some other control acts on the value of the `Text` property (e.g. a textbox used for filtering a list), the placeholder will be used for filtering. The placeholder value should only be used for displaying, therefore it is not a good idea to replace the `Text` property temporarily. – Roland Illig Aug 27 '16 at 09:36
  • 2
    Neat solution, I like it. I would add these usings on top of the class, in order to make it work: `using System; using System.Drawing; using System.Windows.Forms;` Thanks for this! – Eldoïr Nov 10 '17 at 08:55
  • 1
    Definitely holding onto this little treasure :) – blind Skwirl Dec 10 '20 at 21:48
  • Excellent! That plugged in nicely. Thank you :) – WiiLF Nov 09 '21 at 03:41
23

This is not my code, but I use it a lot and it works perfect... XAML ONLY

<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>
Esperento57
  • 16,521
  • 3
  • 39
  • 45
Jaun Lloyd
  • 269
  • 2
  • 2
  • 2
    Works like a charm, and if you add a trigger to IsFocused by replacing the `DataTrigger` by the following `MultiDataTrigger`, it works even better in my humble opinion: ` ` – Akku Dec 05 '19 at 12:22
11

Attached properties to the rescue:

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

        SetPlaceholder(dependencyObject, args.NewValue as string);

        if (!tb.IsFocused)
            ShowPlaceholder(tb);
    }

    private static void OnLostFocus(object sender, RoutedEventArgs routedEventArgs)
    {
        ShowPlaceholder(sender as TextBox);
    }

    private static void OnGotFocus(object sender, RoutedEventArgs routedEventArgs)
    {
        HidePlaceholder(sender as TextBox);
    }

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

    private static void ShowPlaceholder(TextBox textBox)
    {
        if (string.IsNullOrWhiteSpace(textBox.Text))
        {
            textBox.Text = GetPlaceholder(textBox);
        }
    }

    private static void HidePlaceholder(TextBox textBox)
    {
        string placeholderText = GetPlaceholder(textBox);

        if (textBox.Text == placeholderText)
            textBox.Text = string.Empty;
    }
}

Usage:

<TextBox Text="hi" local:TextboxExtensions.Placeholder="Hello there"></TextBox>
Serg
  • 6,742
  • 4
  • 36
  • 54
Dbl
  • 5,634
  • 3
  • 41
  • 66
  • Thanks for providing this nice solution. However, using your solution, results in a) black placeholder text instead of a light-gray one and b) show no placeholder text upon application start (but after focusing and then setting focus somewhere else). Would you mind improving your answer in this regard? – Yoda Sep 15 '16 at 14:57
  • 1
    @Yoda If i manage not to forget it until i get home i will look into improving it, yeah - why not – Dbl Sep 15 '16 at 15:49
  • 1
    Blank placeholder until focusing/unfocusing fixed. – Serg Dec 08 '19 at 20:29
  • @Sergey thanks for the fix - would you mind, add code for customizing the placeholder's text color? – Yoda Jul 09 '20 at 14:57
  • 1
    @Yoda Hi, I don't mind if it's done carefully and doesn't break anything. – Serg Jul 09 '20 at 18:14
  • @Sergey Seems like you got me wrong, sorry about that. I was asking for your guidance/support on how such code, e. g. what's needed where, would look like so that I can style the placeholder text via `Style="{StaticResource MyPlaceholderTextBoxStyle}"`.. – Yoda Jul 09 '20 at 22:22
  • 1
    @Yoda, sorry, I haven't been working with WPF for a while, I don't even have it installed at the moment. You could add another dependency property named `PlaceholderColor` with `typeof(Brush)`. Then change `textBox.Foreground` property in the `ShowPlaceholder` method and restore it back in the `HidePlaceholder` method. – Serg Jul 11 '20 at 15:37
  • @Sergey sorry to hear about that - UWP & Co. taught me that XAML would be the way to go.. Though, you've still helped me getting through with the rest of your comment pointing me in the right direction. So, thanks a lot for that! +1 – Yoda Jul 13 '20 at 08:10
7

While using the EM_SETCUEBANNER message is probably simplest, one thing I do not like is that the placeholder text disappears when the control gets focus. That's a pet peeve of mine when I'm filling out forms. I have to click off of it to remember what the field is for.

So here is another solution for WinForms. It overlays a Label on top of the control, which disappears only when the user starts typing.

It's certainly not bulletproof. It accepts any Control, but I've only tested with a TextBox. It may need modification to work with some controls. The method returns the Label control in case you need to modify it a bit in a specific case, but that may never be needed.

Use it like this:

SetPlaceholder(txtSearch, "Type what you're searching for");

Here is the method:

/// <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;
}
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
6

Based on ExceptionLimeCat's answer, an improvement:

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;
    }
}
Vitalis Hommel
  • 990
  • 2
  • 8
  • 20
5

I know this is an old thread, but .NET Core and .NET 5.0 have implemented the TextBox.PlaceholderText Property.

https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.textbox.placeholdertext?view=net-5.0

Amal K
  • 4,359
  • 2
  • 22
  • 44
synkro
  • 414
  • 7
  • 9
3

This would mean you have a button which allows you to do an action, such as logging in or something. Before you do the action you check if the textbox is filled in. If not it will replace the text

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

It's kind of cheesy but checking the text for the value you're giving it is the best I can do atm, not that good at c# to get a better solution.

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
VJamie
  • 616
  • 3
  • 14
2

You can get the default Template, modify it by overlaying a TextBlock, and use a Style to add triggers that hide and show it in the right states.

Community
  • 1
  • 1
H.B.
  • 166,899
  • 29
  • 327
  • 400
2
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"/>
Saef Myth
  • 143
  • 1
  • 2
  • 11
  • Please explain your answer instead of just dumping a bunch of code into your answer. – Nic Feb 08 '17 at 19:31
2

Here I come with this solution inspired by @Kemal Karadag.

I noticed that every solution posted here is relying on the focus,

While I wanted my placeholder to be the exact clone of a standard HTML placeholder in Google Chrome.

Instead of hiding/showing the placeholder when the box is focused,

I hide/show the placeholder depending on the text length of the box:

If the box is empty, the placeholder is shown, and if you type in the box, the placeholder disappears.

As it is inherited from a standard TextBox, you can find it in your Toolbox!

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();
        }
    }
}
Eldoïr
  • 109
  • 1
  • 11
2

This is a extension method for the texbox. Simply Add the Placeholder Text programmatically:

myTextBox.AddPlaceholderText("Hello World!");

The extension method:

public static void AddPlaceholderText(this TextBox textBox, string placeholderText)
        {
            if (string.IsNullOrWhiteSpace(textBox.Text))
                textBox.Text = placeholderText;
            textBox.SetResourceReference(Control.ForegroundProperty,
                textBox.Text != placeholderText
                    ? "SystemControlForegroundBaseHighBrush"
                    : "SystemControlForegroundBaseMediumBrush");
            var ignoreSelectionChanged = false;
            textBox.SelectionChanged += (sender, args) =>
            {
                if (ignoreSelectionChanged) { ignoreSelectionChanged = false; return; }
                if (textBox.Text != placeholderText) return;
                ignoreSelectionChanged = true;
                textBox.Select(0, 0);
            };
            var lastText = textBox.Text;
            var ignoreTextChanged = false;
            textBox.TextChanged += (sender, args) =>
            {
                if (ignoreTextChanged) { ignoreTextChanged = false; return; }
                if (string.IsNullOrWhiteSpace(textBox.Text))
                {
                    ignoreTextChanged = true;
                    textBox.Text = placeholderText;
                    textBox.Select(0, 0);
                }
                else if (lastText == placeholderText)
                {
                    ignoreTextChanged = true;
                    textBox.Text = textBox.Text.Substring(0, 1);
                    textBox.Select(1, 0);
                }

                textBox.SetResourceReference(Control.ForegroundProperty,
                    textBox.Text != placeholderText
                        ? "SystemControlForegroundBaseHighBrush"
                        : "SystemControlForegroundBaseMediumBrush");
                lastText = textBox.Text;
            };
        }

Happy coding, BierDav

BierDav
  • 1,219
  • 1
  • 10
  • 27
1

I came up with a method that worked for me, but only because I was willing to use the textbox name as my placeholder. See below.

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;
        }
    }
CBC_NS
  • 1,961
  • 4
  • 27
  • 47
0

Try the following code:

<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>
Nalan Madheswaran
  • 10,136
  • 1
  • 57
  • 42
0

you can also do that when the mouse clicks, let's suppose your placeholder text is "User_Name"

 private void textBox1_MouseClick(object sender, MouseEventArgs e)
 {
     if(textBox1.Text == "User_Name")
          textBox1.Text = "";
 }
xpy
  • 5,481
  • 3
  • 29
  • 48
Adiii
  • 54,482
  • 7
  • 145
  • 148
0
    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;
            }
        };
    }
  • 5
    The question is already solved, whats using added value of this answer? There is no explanation add all, try to explain it. – Jannik Jan 15 '16 at 06:19
0

Instead of using the .Text property of a TextBox, I overlayed a TextBlock with the placeholder. I couldn't use the .Text property because this was binded to an Event.

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

Result: enter image description here

andy
  • 531
  • 5
  • 16
0

You could also try in this way..

call the function

TextboxPlaceHolder(this.textBox1, "YourPlaceHolder");

write this function

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

        };
}
Ramgy Borja
  • 2,330
  • 2
  • 19
  • 40
0

there are BETTER solutions, but the easiest solution is here: set the textbox text to your desired string then create a function that deletes the text, have that function fire on textbox Focus Enter event

Jar
  • 1,766
  • 1
  • 21
  • 27
0

I wrote a reusable custom control, maybe it can help someone that need to implement multiple placeholder textboxes in his project.
here is the custom class with implementation example of an instance, you can test easily by pasting this code on a new winforms project using 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();
            }
        }
    }
}
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52
0

Let's extend the TextBox with PlcaeHoldText and PlaceHoldBackround. I stripped some code form my project.

say goodbye to Grid or Canvas!

<TextBox x:Class="VcpkgGui.View.PlaceHoldedTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:VcpkgGui.View"
             mc:Ignorable="d"
             Name="placeHoldTextBox"
             TextAlignment="Left"
         >
    <TextBox.Resources>
        <local:FrameworkWidthConverter x:Key="getElemWidth"/>
        <local:FrameworkHeightConverter x:Key="getElemHeight"/>
        <VisualBrush x:Key="PlaceHoldTextBrush" TileMode="None" Stretch="None" AlignmentX="Left" AlignmentY="Center" Opacity="1">
            <VisualBrush.Visual>
                <Border Background="{Binding ElementName=placeHoldTextBox, Path=PlaceHoldBackground}"
                        BorderThickness="0"
                        Margin="0,0,0,0"
                        Width="{Binding Mode=OneWay, ElementName=placeHoldTextBox, Converter={StaticResource getElemWidth}}"
                        Height="{Binding Mode=OneWay, ElementName=placeHoldTextBox, Converter={StaticResource getElemHeight}}"
                        >
                    <Label Content="{Binding ElementName=placeHoldTextBox, Path=PlaceHoldText}"
                           Background="Transparent"
                           Foreground="#88000000"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Stretch"
                           HorizontalContentAlignment="Left"
                           VerticalContentAlignment="Center"
                           ClipToBounds="True"
                           Padding="0,0,0,0"
                           FontSize="14"
                           FontStyle="Normal"
                           Opacity="1"/>
                </Border>
            </VisualBrush.Visual>
        </VisualBrush>
    </TextBox.Resources>
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Text" Value="{x:Null}">
                    <Setter Property="Background"  Value="{StaticResource PlaceHoldTextBrush}"/>
                </Trigger>
                <Trigger Property="Text" Value="">
                    <Setter Property="Background"  Value="{StaticResource PlaceHoldTextBrush}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace VcpkgGui.View
{
    /// <summary>
    /// PlaceHoldedTextBox.xaml 的交互逻辑
    /// </summary>
    public partial class PlaceHoldedTextBox : TextBox
    {

        public string PlaceHoldText
        {
            get { return (string)GetValue(PlaceHoldTextProperty); }
            set { SetValue(PlaceHoldTextProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PlaceHolderText.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PlaceHoldTextProperty =
            DependencyProperty.Register("PlaceHoldText", typeof(string), typeof(PlaceHoldedTextBox), new PropertyMetadata(string.Empty));



        public Brush PlaceHoldBackground
        {
            get { return (Brush)GetValue(PlaceHoldBackgroundProperty); }
            set { SetValue(PlaceHoldBackgroundProperty, value); }
        }

        public static readonly DependencyProperty PlaceHoldBackgroundProperty =
            DependencyProperty.Register(nameof(PlaceHoldBackground), typeof(Brush), typeof(PlaceHoldedTextBox), new PropertyMetadata(Brushes.White));

        public PlaceHoldedTextBox() :base()
        {
            InitializeComponent();
        }
    }

    [ValueConversion(typeof(FrameworkElement), typeof(double))]
    internal class FrameworkWidthConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value is FrameworkElement elem)
                return double.IsNaN(elem.Width) ? elem.ActualWidth : elem.Width;
            else
                return DependencyProperty.UnsetValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }
    }

    [ValueConversion(typeof(FrameworkElement), typeof(double))]
    internal class FrameworkHeightConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is FrameworkElement elem)
                return double.IsNaN(elem.Height) ? elem.ActualHeight : elem.Height;
            else
                return DependencyProperty.UnsetValue;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return DependencyProperty.UnsetValue;
        }
    }

}
Fa鸽
  • 21
  • 3
0

Just add a placeholder attribute to the TextBox

            <asp:TextBox ID="Text1" runat="server" 
                TextMode="MultiLine" 
                Rows="2" 
                Columns="20" 
                placeholder="Enter text here..." />
            
Eduardo
  • 78
  • 3
-1

txtUsuario.Attributes.Add("placeholder", "Texto");

-1

Very effective solution here for WindowsForms TextBox control. (not sure about XAML).

This will work in Multliline mode also.

Probably it may be extended for other controls, like ComboBox control (not checked)

Anton Norko
  • 2,166
  • 1
  • 15
  • 20
-2

Works like a charm.

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);
        }
    }
}
Sergey
  • 581
  • 1
  • 5
  • 12