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


85

Tengo un formulario que contiene un TextBoxen C # que configuré en una cadena de la siguiente manera:

textBox.Text = str;

Cuando se muestra el formulario, ¿por qué el texto en el cuadro de texto aparece resaltado / seleccionado?


Su pregunta podría estar relacionada con stackoverflow.com/questions/1140250/…
DarenW

¿Conseguiste solucionar esto? ¿Cómo arreglaste esto?
fletcher

@fletcher: Todavía no he tenido tiempo de mirarlo. Daré la respuesta en unos días.
CJ7

Puede agregar una etiqueta vb.net, ya que el problema es realmente el mismo y la respuesta aceptada también es válida
Andrea Antonangeli

La respuesta de BenSmith relacionada con la visualización del orden de tabulación será muy útil en este escenario.
Samitha Chathuranga

Respuestas:


128

El cuadro de texto tiene un valor TabIndexde 0 y se TabStopestablece en verdadero. Esto significa que se le dará foco al control cuando se muestre el formulario.

Puede darle a otro control el 0 TabIndex(si hay uno) y darle al cuadro de texto un índice de pestaña diferente (> 0), o establecer TabStopen falso para que el cuadro de texto evite que esto suceda.


1
¿Está seguro de que el cuadro de texto TabIndex está establecido en 0? ¿Viene de su comportamiento?
26071986

@ 26071986 - Bueno, hice una prueba rápida. Si, en un formulario con un cuadro de texto y un botón, cambio el texto dentro del cuadro de texto en el constructor cuando el tabindex se establece en 0, el texto se resalta. Si el botón tiene el índice de tabulación 0 y el índice de tabulación del cuadro de texto es> 0, el texto no se resalta.
fletcher

De hecho, parece tener que ver con TabIndex, solo que cambié todos los índices de pestañas de mis elementos de manera apropiada (eso pensé). Resulta que los grupos también tienen índices de pestañas que debes cambiar, así como todos los elementos que los contienen. Entonces, aunque configuré pestañas de elementos del 1 al 9, un grupo todavía tenía 0, por lo que el cuadro de texto en ese grupo se convirtió en el primer elemento activado (por lo tanto, tenía su contenido resaltado).
deed02392

1
No está necesariamente relacionado con tener TabIndex = 0, pero ciertamente sucede si el TextBox tiene el TabIndex MÁS BAJO del formulario. Para verificar: establezca TabIndex = 5 en el TextBox y establezca un número mayor que 5 en todos los TabIndex de los otros controles del formulario.
Andrea Antonangeli

Esto también sucede cuando selecciona una nueva TabPage en un TabControl. La misma solución funciona.
JonP

44

El comportamiento predeterminado de un TextBox en Windows Forms es resaltar todo el texto si se enfoca por primera vez al tabularlo, pero no si se hace clic en él. Podemos ver esto en el reflector mirando el TextBox's OnGotFocus()de anulación:

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 Textautor de la propiedad restablece ciegamente esa selectionSetvariable 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 TextBox y una pestaña 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 cursor (y la longitud de selección de cero). Pero si configuramos programáticamente nuevo Text, y volvemos a tabular en el TextBox, entonces todo el texto se seleccionará nuevamente.

Si usted es como yo y encuentra este comportamiento molesto e inconsistente, entonces hay dos formas de solucionar este problema.

El primero, y probablemente el más fácil, es simplemente activar la configuración de selectionSetllamando DeselectAll()al formulario Load()y siempre que los Textcambios:

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

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

( DeselectAll()Sólo conjuntos SelectionLengtha cero. En realidad es SelectionStartque voltea la TextBox's selectionSetvariables. En el caso anterior, el llamado a DeselectAll()no es necesaria, ya que estamos estableciendo el principio hasta el final del texto. Pero si lo ponemos a cualquier otra posición, al igual el comienzo del texto, luego 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;
        }
    }
}

Quizás tenga la tentación de no llamar base.OnGotFocus(), pero entonces perderíamos funcionalidad útil en la Controlclase base . Y es posible que tenga la tentación de no meterse con las selectionSettonterías en absoluto y simplemente anular la selección del texto cada vez en OnGotFocus (), pero luego perderíamos el resaltado del usuario si saliera del campo y regresara.

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


31

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. Sólo hay que establecer SelectionStartque 0después de ajustar el texto. ¡Problema resuelto!

Ejemplo:

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

4

También puede elegir el orden de las pestañas para los controles de su formulario abriendo:

Ver-> Orden de tabulación

Tenga en cuenta que esta opción solo está disponible en "Ver" si tiene abierta la vista Diseño de formulario.

Al seleccionar "Orden de tabulación" se abre una vista del formulario que le permite elegir el orden de tabulación deseado haciendo clic en los controles.


1
Eso me ayudó mucho. En realidad, el índice de tabulación no importa si nos preocupamos por el orden de tabulación.
Samitha Chathuranga

1

Para quitar el resaltado de un campo de texto, con VS 2013, intente init con:

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

Y agregue el método:

public void myTextBox_GotFocus(object sender, EventArgs e)
{
    myTextBox.SelectionLength=0;
}

Esto haría que el texto se deseleccionara si previamente enfocó el cuadro de texto, seleccionó algún texto en él, se alejó de él y luego lo enfocó nuevamente.
Stewart

0

No he probado esto en C # pero encontré el mismo problema usando un cuadro de diálogo C ++ WIN32. Parece que puedes cambiar el comportamiento volviendo FALSEde OnInitDialog()o WM_INITDIALOG. Espero que esto ayude.


1
No creo que esto ayude mucho, ya que la API de Windows está encapsulada dentro de winforms.
Nathan A
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.