2010-02-18 9 views
8

Ich habe ein Standard-TextBox-Steuerelement, das die "weichen Beschreibungen" wie die Titel- und Tag-Felder in StackOverflow nachahmt. Wenn der Fokus des Benutzers in das Steuerelement eindringt, verbirgt es im Wesentlichen die Beschreibung ("Benutzername") in diesem Fall und legt Ausrichtung und Farbe als ein Standardtextsteuerelement fest. Wenn der Benutzer das Textfeld verlässt, möchte ich prüfen, ob der Benutzer tatsächlich etwas eingegeben hat, und die Benutzernamenanzeige anderweitig anzeigen.Das Ändern eines TextBox-Steuerelements für das Leave-Ereignis verhindert das Ausblenden des Steuerelements.

Zum Beispiel:

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

Leider, wenn ich ein Setup dieser Ereignisse kann der Anwender nicht Registerkarte aus der Benutzerkontrolle. Das Steuerelement flackert einfach und die Steuerung kehrt zum Textbox-Steuerelement selbst zurück, bis der Benutzer etwas eingegeben und den Ereigniskörper übersprungen hat.

Wenn ich im Ereignis this.SelectNextControl() aufrufen, dann tritt das Ereignis in eine Endlosschleife.

Kann jemand sehen, was ich falsch mache?

+0

Interessante .. Scheint mit Textalign etwas zu sein. Wenn ich das kommentiere, scheint das okay zu sein. – SwDevMan81

+0

+1 Gut gefunden. Hoffentlich funktioniert eines der Workarounds für Sie, obwohl keines optimal ist. Könnte dies möglicherweise in MSDN Foren (http://social.msdn.microsoft.com/Forums/en-US/categories) veröffentlichen, um zu sehen, ob sie wissen, was los ist. – SwDevMan81

Antwort

6

Sieht anders aus (Verwenden von Reflector, um zu sehen, dass es sich wieder auf das Steuerelement konzentriert, wenn der Fokus zu Beginn vorhanden war). Ich denke, es ist ein Fehler, aber es sieht so aus, als ob sie die RecreateHandleCore-Funktion wieder verwenden, um den Text neu zu zeichnen. So wäre ein weiterer Weg, um die Textbox zuerst zu konzentrieren weg zu sein, dann weiter:

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 für die Zeit zu überprüfen, was in Reflector tatsächlich vor sich geht. – Bill

3

Durch Festlegen der TextAlign-Eigenschaft für das TextBox-Steuerelement wird der Fokus auf dieses Steuerelement zurückgesetzt. Das scheint ein Fehler zu sein.

Hier ist eine schnelle Lösung:

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

(wenn auch etwas von einem Hack um unerwartetes Verhalten). Deaktivieren Sie einfach das Steuerelement, bevor Sie die Ausrichtung ändern. Ein weiterer "Fix" wäre, die Objekte nach links auszurichten oder zu messen, wie viele Leerzeichen einzufügen sind, um den Text zu zentrieren.

+0

+1 :) Wenn nichts anderes, ich muss einen Kollegen Bill upvote! Nur weil ich stattdessen die "Fokus" -Methode verwendet habe, flackerte sie etwas weniger auf meiner Maschine. –

3

Verwenden 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. Der einzige Grund, warum ich die focus() -Lösung hier gewählt habe, ist, dass sie delokalisiert, was die Funktion aus ihrer Definition machen soll. –

+0

Diese Lösung funktioniert meistens "zufällig", dh normalerweise wird der BeginInvoke-Delegat so geplant, dass er "später" heißt, dh nachdem der Fokus vom Steuerelement entfernt wurde - aber es ist nicht garantiert, dass er später ist - der OnLeave-Code könnte tatsächlich ausgeführt werden, bevor der Ereignishandler tbUsername_Leave abgeschlossen wird und der Fokus sich vom ursprünglichen Steuerelement entfernt. – Bill

+0

Wo ist der Beweis, dass es nicht garantiert ist? Ich kann nur neu festlegen, dass BeginInvoke weitgehend PostMessage entspricht und eine registrierte Nachricht in der Windows-Nachrichtenwarteschlange für die spätere Verarbeitung in Warteschlangen stellt. Es wird dann von der Anwendungspumpe aufgenommen und auf dem Haupt-GUI-Thread ausgeführt. –

Verwandte Themen