99

I have a form containing a TextBox in C# which I set to a string as follows:

textBox.Text = str;

When the form is displayed, why does the text in the texbox appear highlighted/selected?

gog
  • 1,220
  • 11
  • 30
CJ7
  • 22,579
  • 65
  • 193
  • 321

7 Answers7

148

The text box has a TabIndex of 0 and TabStop set to true. This means that the control will be given focus when the form is displayed.

You can either give another control the 0 TabIndex (if there is one) and give the text box a different tab index (>0), or set TabStop to false for the text box to stop this from happening.

Rag
  • 6,405
  • 2
  • 31
  • 38
fletcher
  • 13,380
  • 9
  • 52
  • 69
  • 1
    Are you sure that textbox TabIndex is set to 0? It comes out of its behaviour? – 26071986 Aug 06 '10 at 06:47
  • @26071986 - Well, I ran a quick test. If, on a form with one text box and a button, I change the text within the textbox in the constructor when the tabindex is set to 0 the text is highlighted. If the button has the 0 tab index and the textbox tabindex is >0, the text is not highlighted. – fletcher Aug 06 '10 at 06:55
  • It does indeed seem to be to do with TabIndex - only I changed all my elements tab indices appropriately (so I thought). Turns out that Groups have tab indices too which you need to change as well as all their containing elements. So whilst I'd set up element tabs from 1-9, a group still had 0, so the text box in that group became the first activated element (hence had its contents highlighted). – deed02392 Oct 08 '13 at 11:07
  • 1
    It is not necessarily related to having TabIndex = 0, but it certainly happens if the TextBox has the LOWEST TabIndex of the form. To verify: set TabIndex = 5 in the TextBox and set a number greater then 5 in all the TabIndexs of the other controls of the form. – Andrea Antonangeli Oct 18 '14 at 11:09
  • This also happens when you select a new TabPage in a TabControl. The same solution works. – JonP Jan 24 '20 at 17:50
  • Thanks! I just needed to change the ```TabStop``` property from ```True``` -> ```False``` then, everything is solved. – ewu11 Mar 25 '22 at 04:35
48

The default behavior of a TextBox in Windows Forms is to highlight all of the text if it gets focused for the first time by tabbing into it, but not if it is clicked into. We can see this in Reflector by looking at the TextBox's OnGotFocus() override:

protected override void OnGotFocus(EventArgs e)
{
    base.OnGotFocus(e);
    if (!this.selectionSet)
    {
        this.selectionSet = true;
        if ((this.SelectionLength == 0) && (Control.MouseButtons == MouseButtons.None))
        {
            base.SelectAll();
        }
    }
}

It's that if statement that is causing the behavior that we don't like. Furthermore, to add insult to injury, the Text property's setter blindly resets that selectionSet variable whenever the text is re-assigned:

public override string Text
{
    get
    {
        return base.Text;
    }
    set
    {
        base.Text = value;
        this.selectionSet = false;
    }
}

So if you have a TextBox and tab into it, all the text will be selected. If you click into it, the highlight is removed, and if you re-tab into it, your caret position (and selection length of zero) is preserved. But if we programmatically set new Text, and tab into the TextBox again, then all of the text will be selected again.

If you are like me and find this behavior annoying and inconsistent, then there are two ways around this problem.

The first, and probably the easiest, is to simply trigger the setting of selectionSet by calling DeselectAll() on form Load() and whenever the Text changes:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    this.textBox2.SelectionStart = this.textBox2.Text.Length;
    this.textBox2.DeselectAll();
}

(DeselectAll() just sets SelectionLength to zero. It's actually SelectionStart that flips the TextBox's selectionSet variable. In the above case, the call to DeselectAll() is not necessary since we are setting the start to the end of the text. But if we set it to any other position, like the start of the text, then calling it is a good idea.)

The more permanent way is to create our own TextBox with the desired behavior through inheritance:

public class NonSelectingTextBox : TextBox
{
    // Base class has a selectionSet property, but its private.
    // We need to shadow with our own variable. If true, this means
    // "don't mess with the selection, the user did it."
    private bool selectionSet;

    protected override void OnGotFocus(EventArgs e)
    {
        bool needToDeselect = false;

        // We don't want to avoid calling the base implementation
        // completely. We mirror the logic that we are trying to avoid;
        // if the base implementation will select all of the text, we
        // set a boolean.
        if (!this.selectionSet)
        {
            this.selectionSet = true;

            if ((this.SelectionLength == 0) && 
                (Control.MouseButtons == MouseButtons.None))
            {
                needToDeselect = true;
            }
        }

        // Call the base implementation
        base.OnGotFocus(e);

        // Did we notice that the text was selected automatically? Let's
        // de-select it and put the caret at the end.
        if (needToDeselect)
        {
            this.SelectionStart = this.Text.Length;
            this.DeselectAll();
        }
    }

    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            base.Text = value;

            // Update our copy of the variable since the
            // base implementation will have flipped its back.
            this.selectionSet = false;
        }
    }
}

You maybe tempted to just not call base.OnGotFocus(), but then we would lose useful functionality in the base Control class. And you might be tempted to not mess with the selectionSet nonsense at all and simply deselect the text every time in OnGotFocus(), but then we would lose the user's highlight if they tabbed out of the field and back.

Ugly? You betcha. But it is what it is.

Nicholas Piasecki
  • 25,203
  • 5
  • 80
  • 91
35

The answers to this question helped me a lot with a similar problem, but the simple answer is only hinted at with a lot of other complex suggestions. Just set SelectionStart to 0 after setting your Text. Problem solved!

Example:

yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;
zx485
  • 28,498
  • 28
  • 50
  • 59
Frank T. Clark
  • 459
  • 4
  • 8
4

You can also choose the tab order for your form's controls by opening:

View->Tab Order

Note that this option is only available in "View" if you have the Form design view open.

Selecting "Tab Order" opens a view of the Form which allows you to choose the desired tab order by clicking on the controls.

Ben Smith
  • 19,589
  • 6
  • 65
  • 93
1

To unhighlight a text field, with VS 2013, try init with:

myTextBox.GotFocus += new System.EventHandler(this.myTextBox_GotFocus);

And add the method:

public void myTextBox_GotFocus(object sender, EventArgs e)
{
    myTextBox.SelectionLength=0;
}
Marty
  • 932
  • 6
  • 8
  • This would cause the text to be deselected if you previously focused the text box, selected some text in it, moved away from it and then focused it again. – Stewart Oct 23 '20 at 12:41
0

I haven't tested this on C# but I ran into the same issue using a C++ WIN32 dialog box. Is seems like you can change the behavior by returning FALSE from OnInitDialog() or WM_INITDIALOG. Hope this helps.

J. Scott Elblein
  • 4,013
  • 15
  • 58
  • 94
0

Here is what worked for me

public void SetNotes(string notes)
    {
        notesTextBox.Text = notes;

        notesTextBox.Select();
        notesTextBox.SelectionLength = 0;
        notesTextBox.SelectionStart = notes.Length;//place cursor at end of text
    }