C# 在Leave事件上修改TextBox控件可防止选项卡脱离控制

C# 在Leave事件上修改TextBox控件可防止选项卡脱离控制,c#,.net,winforms,textbox,C#,.net,Winforms,Textbox,我有一个标准的文本框控件,我试图模仿StackOverflow上标题和标签框中的“软描述”。本质上,当用户的焦点进入控件时,在本例中隐藏了描述(“用户名”),并将对齐方式和颜色设置为标准文本控件的对齐方式和颜色。当用户离开文本框时,我想检查用户是否真的输入了任何内容,否则将重新显示用户名 例如: private void tbUsername_Enter(object sender, EventArgs e) { if (tbUsername.TextAlign

我有一个标准的文本框控件,我试图模仿StackOverflow上标题和标签框中的“软描述”。本质上,当用户的焦点进入控件时,在本例中隐藏了描述(“用户名”),并将对齐方式和颜色设置为标准文本控件的对齐方式和颜色。当用户离开文本框时,我想检查用户是否真的输入了任何内容,否则将重新显示用户名

例如:

    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";
        }
    }
不幸的是,当我设置这些事件时,用户无法将选项卡从username控件中移出。控件只是闪烁,控件返回到textbox控件本身,直到用户输入了一些内容,跳过事件体

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


有人知道我做错了什么吗?

在TextBox控件上设置TextAlign属性会将焦点返回到该控件。这看起来像个虫子

下面是一个快速解决方案:

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

(尽管有点像是针对意外行为的黑客攻击)。只需在更改对齐方式之前禁用控件。另一个“修复”方法是保持事物向左对齐,或者测量要插入多少空格来模拟文本居中。

看起来像是围绕文本的另一种方式(使用反射器查看它是否重新聚焦控件,如果焦点在那里)。我认为这是一个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;
     }
  }
使用


有意思。。似乎与TextAlign有关。如果我把它评论出来,似乎还可以。希望其中一种解决方法能对你有效,尽管两者都不是最优的。我可能会把这篇文章发到MSDN论坛()上,看看他们是否知道发生了什么事。+1:)如果没有其他事情,我必须投票支持一项提案!我使用
focus
方法的唯一原因是它在我的机器上闪烁的次数少了一点。我选择focus()解决方案而不是这个解决方案的唯一原因是,它根据函数的定义对函数应该做的事情进行了非定域处理。这个解决方案主要是“偶然”起作用的,也就是说,通常BeginInvoke委托会被安排在“稍后”调用,在焦点从控件移开后(但不保证以后会移开),OnLeave代码实际上可以在tbUsername\u Leave事件处理程序完成并且焦点从原始控件移开之前运行。哪里有证据证明它不能得到保证?我只能重新声明BeginInvoke基本上等同于PostMessage,并将已注册的消息排入windows消息队列以供以后处理。然后,它被应用程序消息泵接收,并在主GUI线程上执行。+1用于花时间检查Reflector中的实际情况。
    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";
        }
    }