2010-02-18 12 views
8

Tengo un control TextBox estándar que trato de imitar a las "descripciones suaves" como las que se encuentran en los cuadros de título y etiquetas en StackOverflow. Esencialmente, cuando el enfoque del usuario ingresa al control, oculta la descripción ("Nombre de usuario") en este caso, y establece que la alineación y el color sean los de un control de texto estándar. Cuando el usuario abandona el cuadro de texto, quiero verificar si el usuario realmente ingresó algo, y poner de otra manera el nombre de usuario en la pantalla de respaldo.Al modificar un control TextBox en el evento Leave se excluye el control

Por ejemplo:

private void tbUsername_Enter(object sender, EventArgs e) 
    { 
     if (tbUsername.TextAlign == HorizontalAlignment.Center) 
     { 
      tbUsername.TextAlign = HorizontalAlignment.Left; 
      tbUsername.ForeColor = SystemColors.ControlText; 
      tbUsername.Text = String.Empty; 
     } 
    } 

    private void tbUsername_Leave(object sender, EventArgs e) 
    { 
     if (tbUsername.Text == String.Empty) 
     { 
      tbUsername.TextAlign = HorizontalAlignment.Center; 
      tbUsername.ForeColor = SystemColors.InactiveCaption; 
      tbUsername.Text = "Username"; 
     } 
    } 

Por desgracia, cuando configuración de estos eventos, el usuario no puede pestaña fuera del control de usuario. El control simplemente parpadea y el control vuelve al control de la caja de texto hasta que el usuario haya ingresado algo, omitiendo el cuerpo del evento.

Si llamo al this.SelectNextControl() en el evento, el evento entra en un bucle infinito.

¿Alguien ve lo que estoy haciendo mal?

+0

Interesante .. parece ser algo con TextAlign. Si lo comento, parece estar bien. – SwDevMan81

+0

+1 Buen descubrimiento. Afortunadamente, una de las alternativas funcionará para usted, aunque ninguna es óptima. Probablemente podría publicar esto en MSDN Forums (http://social.msdn.microsoft.com/Forums/en-US/categories) para ver si saben qué está sucediendo. – SwDevMan81

Respuesta

6

Parece otra forma de evitarlo (utilizando el reflector para ver si se enfoca de nuevo en el control si el foco estaba allí para comenzar). Creo que es un error, pero parece que solo estaban reutilizando la función RecreateHandleCore para volver a dibujar el texto. Así que de otra manera sería centrarse fuera de la caja de texto primero, y luego continuar:

private void LeaveEvent(object sender, EventArgs e) 
    { 
    if (String.IsNullOrEmpty(tbUsername.Text)) 
    { 
     tbUsername.Text = USER_NAME; 
     tbUsername.ForeColor = SystemColors.InactiveCaption; 
     this.Focus(); 
     tbUsername.TextAlign = HorizontalAlignment.Center; 
    } 
    } 
+0

+1 por tomarse el tiempo para comprobar qué está sucediendo realmente en Reflector. – Bill

3

Establecer la propiedad TextAlign en el control TextBox devuelve el foco a ese control. Eso parece un error.

Aquí es una solución rápida:

tbUsername.Enabled = false; 
tbUsername.ForeColor = SystemColors.InactiveCaption; 
tbUsername.Text = "Username"; 
tbUsername.TextAlign = HorizontalAlignment.Center; 
tbUsername.Enabled = true; 

(aunque algo de un corte alrededor de un comportamiento inesperado). Simplemente desactive el control antes de cambiar la alineación. Otra "solución" sería mantener las cosas alineadas a la izquierda o medir cuántos espacios insertar para simular el centrado del texto.

+0

+1 :) ¡Si nada más, tengo que apoyar a un compañero Bill! La única razón por la que utilicé el método 'focus' es que parpadeó un poco menos en mi máquina. –

3

Uso BeginInvoke

private void tbUsername_Leave(object sender, EventArgs e) 
    { 
     BeginInvoke(new MethodInvoker(OnLeave)); 
    } 

    private void OnLeave() 
    { 
     if (tbUsername.Text == String.Empty) 
     { 
      tbUsername.TextAlign = HorizontalAlignment.Center; 
      tbUsername.ForeColor = SystemColors.InactiveCaption; 
      tbUsername.Text = "Username"; 
     } 
    } 
+1

+1. La única razón por la que elegí la solución de focus() sobre esta es que deslocaliza lo que la función debería hacer desde su definición. –

+0

Esta solución funciona principalmente "por accidente", es decir, normalmente el delegado de BeginInvoke se programará para llamarse "más tarde", es decir, después de que el foco se aleje del control, pero no se garantiza que sea más tarde, el código OnLeave podría ejecutarse antes de que el controlador de eventos tbUsername_Leave se complete y el foco se aleje del control original. – Bill

+0

¿Dónde está la prueba de que no está garantizado? Solo puedo volver a afirmar que BeginInvoke es casi equivalente a PostMessage y encola un mensaje registrado en la cola de mensajes de Windows para su posterior procesamiento. Luego es recogido por la bomba de mensajes de aplicaciones y ejecutado en el hilo principal de la GUI. –

Cuestiones relacionadas