¿Por qué el texto en TextBox está resaltado (seleccionado) cuando se muestra el formulario?

¿Por qué el texto en TextBox está resaltado (seleccionado) cuando se muestra el formulario?

El cuadro de texto tiene un TabIndex de 0 y TabStop establecido en verdadero. Esto significa que el control recibirá el foco cuando se muestre el formulario.

Puedes darle a otro control el 0 TabIndex (si hay uno) y asigne al cuadro de texto un índice de tabulación diferente (>0), o configure TabStop a falso para que el cuadro de texto evite que esto suceda.


El comportamiento predeterminado de un TextBox en Windows Forms es resaltar todo el texto si se enfoca por primera vez tabulando en él, pero no si se hace clic en él. Podemos ver esto en Reflector mirando el TextBox de OnGotFocus() anular:

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

Es esa declaración if la que está causando el comportamiento que no nos gusta. Además, para colmo de males, el Text el setter de la propiedad restablece ciegamente ese selectionSet variable cada vez que se reasigna el texto:

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

Entonces, si tiene un cuadro de texto y entra en él, se seleccionará todo el texto. Si hace clic en él, se elimina el resaltado, y si vuelve a tabular, se conserva la posición del símbolo de intercalación (y la longitud de selección de cero). Pero si configuramos programáticamente new Text y tabula nuevamente en el cuadro de texto, luego todo el texto se seleccionará nuevamente.

Si eres como yo y encuentras este comportamiento molesto e inconsistente, entonces hay dos formas de evitar este problema.

El primero, y probablemente el más fácil, es simplemente activar la configuración de selectionSet llamando al DeselectAll() en el formulario Load() y siempre que el Text cambios:

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

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

(DeselectAll() simplemente establece SelectionLength a cero. En realidad es SelectionStart que voltea el TextBox de selectionSet variable. En el caso anterior, la llamada a DeselectAll() no es necesario ya que estamos configurando el principio hasta el final del texto. Pero si lo configuramos en cualquier otra posición, como el comienzo del texto, entonces llamarlo es una buena idea).

La forma más permanente es crear nuestro propio TextBox con el comportamiento deseado a través de la herencia:

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

Tal vez tengas la tentación de simplemente no llamar a base.OnGotFocus() , pero perderíamos funcionalidad útil en la base Control clase. Y podrías tener la tentación de no meterte con el selectionSet tonterías en absoluto y simplemente deseleccionar el texto cada vez en OnGotFocus(), pero entonces perderíamos el resaltado del usuario si tabulan fuera del campo y regresan.

¿Feo? Puedes apostar. Pero es lo que es.


Las respuestas a esta pregunta me ayudaron mucho con un problema similar, pero la respuesta simple solo se insinúa con muchas otras sugerencias complejas. Solo configura SelectionStart a 0 después de configurar su Texto. ¡Problema resuelto!

Ejemplo:

yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;