1

你能解释为什么会这样吗?以下是重现异常的步骤:

  1. 在表单上拖放一个文本框。添加任何其他可聚焦的控件,例如窗体上的按钮。
  2. 为该 TextBox 添加 2 个事件处理程序,如下所示:

    private void textBox_GotFocus(object sender, EventArgs e){
      ((TextBox)sender).HideSelection = false; //<-- exception highlighted at here.
    }
    
    private void textBox_LostFocus(object sender, EventArgs e){
      ((TextBox)sender).HideSelection = true;
    }
    
  3. 运行窗体,先点击文本框,然后点击按钮再点击文本框,异常会抛出:“Win32Exception - 错误创建窗口句柄”。

该代码只是为了在 textBox 获得焦点并失去焦点时相应地更改 HideSelection 。

更新

我不知道为什么这么不稳定,我创建了另一个项目,现在问题不同了,没有例外,但是一个无限循环使文本框闪烁,表单似乎没有响应,CPU使用率被消耗约 17-20%。最后一个演示仍然打开,该演示仍然Win32Exception抛出。一点头绪都没有。现在两个项目的代码是一样的,但问题是不同的。

4

3 回答 3

2

嗯,有几件事需要注意。

首先,HideSelection不隐藏或取消隐藏选择。它指定当控件失去焦点时是否隐藏(或不隐藏)选择。TextBox所以当它变得专注时改变它是没有意义的。

你在做什么LostFocus是默认的,顺便说一句。GotFocus我猜为什么 Windows API 中存在异常。HideSelection当在焦点更改事件中检查 TextBox 是否具有焦点或尝试隐藏未显示的选择时,可能会出现一些未定义的状态。编辑:这不是第一手的Windows API,而是框架。它会尝试在 HideSelection 的设置器中“重新创建句柄”,如果它被更改(还不知道为什么 - 必须分析源)并且似乎失败(也不知道为什么)。Edit2:最后在 Win32 DestroyWindow 中出现了一些问题 - 这导致跳过了新窗口的创建。也许是因为旧的在焦点更改事件中“正在使用”?

有趣的是,一旦发生异常(对我来说),LostFocus事件就会被触发,然后立即GotFocus引发另一个异常,从而阻塞 GUI。两个任务都HideSelection抛出异常。

此外,当您单击 时TextBox,将自动取消选择任何选择。但是,这不是问题的原因,因为如果您通过按 Tab 更改焦点(其正常行为是恢复焦点),则会引发异常。但这可能是相关的(状态问题)。

如果你真的想恢复选择,你可以这样做:

int selStart;
int selLen;
void textBox1_LostFocus(object sender, EventArgs e)
{
    selStart = textBox1.SelectionStart;
    selLen = textBox1.SelectionLength;
}
void textBox1_GotFocus(object sender, EventArgs e)
{
    BeginInvoke((Action)(() =>
    {
       textBox1.SelectionStart = selStart;
       textBox1.SelectionLength = selLen;
    }));
}
于 2013-06-06T07:12:24.577 回答
2

我重现了这次崩溃。通过在事件处理程序上设置断点,您可以很容易地看到它出错了,注意它们是如何在您的程序炸弹之前一遍又一遍地触发的。解释有点啰嗦,我先给出简短的版本。LostFocus 事件的MSDN 文档给出了严厉的警告,包括注意和警告,指出这是一个危险的低级别事件。出于这个原因,这些事件也隐藏在“属性”窗口中。改用 Enter 和 Leave 事件来解决您的问题。

长版本:TextBox.HideSelection 属性相当特别。它与指定本地 Windows 控件上的某些属性的方式有关。这些控件是使用CreateWindowEx() winapi 函数创建的,它采用 dwExStyle 和 dwStyle 参数,这些标志指定窗口的样式选项。HideSelection 属性就是这样一个样式标志,ES_NOHIDESEL。

当您想要更改属性时,这会出现问题。很难,因为它只能在创建本机控件时指定。Winforms 做了一些非常英勇的事情来解决这个限制,它破坏了本机控件并重新创建它。

委婉地说,这可能会产生非常有趣的副作用。大多数是不可观察的,但您确实可以看到屏幕上的窗口被破坏并重新创建。这就是它闪烁的原因。您的代码的核心问题不可避免地是,因为本机窗口正在被破坏,它也失去了焦点。因此,在您获得 GotFocus 事件之后,LostFocus 事件会立即触发。不幸的是,它再次更改了 HideSelection 属性。这迫使 Winforms 再次重新创建本机控件。

当您的 GotFocus 事件处理程序再次为新的本机控件运行时,这种情况会一遍又一遍地重复。当 Windows 停止它并且不允许创建更多本机窗口时,这最终会结束,一段时间后它会在 10,000 个控件上拔掉插头。这会生成“创建窗口句柄时出错”异常。

Enter 和 Leave 事件应始终用于聚焦事件,它们仅在用户实际移动焦点时触发,并且在由于其他原因(例如此原因)发生时不会触发。同样值得注意的是,像您一样更改 HideSelection 属性根本没有意义,该属性仅在 TextBox 没有焦点时才会产生影响。选择具有焦点时永远不会隐藏。因此,正确的解决方法是删除这些事件处理程序,并在“属性”窗口中将 HideSelection 属性设置为 True。默认值。

于 2013-06-06T08:07:04.620 回答
0

无法为我重现此作品:

private void textBox1_Leave(object sender, EventArgs e)
{
    ((TextBox)sender).HideSelection = false;
}

private void textBox1_Enter(object sender, EventArgs e)
{
    ((TextBox)sender).HideSelection = true;
}
于 2013-06-06T07:09:52.267 回答