2010-02-18 59 views
8

我有哪些我想有模仿“软描述”像那些在StackOverflow上的标题和标签盒发现了一个标准的TextBox控件。实质上,当用户的焦点进入控件时,它在这种情况下隐藏描述(“用户名”),并将对齐和颜色设置为标准文本控件的对齐和颜色。当用户离开文本框时,我想检查用户是否实际输入了任何内容,并将用户名显示备份到其他位置。修改上Leave事件TextBox控件防止Tab键进行控制

例如:

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

不幸的是,当我设置这些事件,用户不能切换出该用户名的控制。控件只是闪烁并控制返回到文本框控件本身,直到用户输入了一些内容,跳过事件主体。

如果我在事件调用this.SelectNextControl(),则该事件进入一个无限循环。

有没有人看到我在做什么错了?

+0

有趣..似乎有什么东西与textAlign设置。如果我发表评论,似乎没问题。 – SwDevMan81 2010-02-18 19:43:03

+0

+1好找。希望其中一个解决方法能够为你工作,尽管这两者都不是最优的。可以将其发布到MSDN论坛(http://social.msdn.microsoft.com/Forums/en-US/categories)以查看他们是否知道发生了什么。 – SwDevMan81 2010-02-18 20:39:44

回答

6

看起来像它周围的另一种方法(使用反射来看看,它并重新聚焦回控制,如果重点在那里开始)。我认为这是一个bug,但看起来他们只是重新使用RecreateHandleCore函数来重绘文本。因此,另一种方法是首先关注过文本框,然后继续:

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用于抽查时间检查Reflector中实际发生的情况。 – Bill 2010-02-18 23:04:51

3

在TextBox控件上设置TextAlign属性会将焦点返回给该控件。这看起来像一个错误。

这里是一个快速的解决办法:

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

(尽管周围的意外行为一个黑客颇有几分)。在更改对齐之前,只需禁用该控件即可。另一个“修复”是将事情保持对齐,或者测量要插入多少空间以模拟文本居中。

+0

+1 :)如果没有其他,我必须upvote一个同胞比尔!我使用'focus'方法的唯一原因是它在我的机器上少了一点点。 – 2010-02-18 21:25:20

3

使用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。我选择focus()解决方案的唯一原因是它将本函数应该从定义中分离出来。 – 2010-02-18 21:34:55

+0

此解决方案主要是“意外”,即通常BeginInvoke委托将被安排为“稍后”调用,也就是说,焦点从控件移开后 - 但它不保证以后 - OnLeave代码实际上可以在tbUsername_Leave事件处理程序完成之前运行,并且焦点从原始控件移开。 – Bill 2010-02-18 23:03:20

+0

证据不能得到保证的地方在哪里? 我只能重新说明BeginInvoke大部分等同于PostMessage,并将注册消息排入窗口消息队列以供以后处理。然后它由应用程序消息泵拾取并在主GUI线程上执行。 – 2010-02-18 23:37:37