Windows 窗体:无法单击以聚焦非***窗体中的 MaskedTextBox

Posted

技术标签:

【中文标题】Windows 窗体:无法单击以聚焦非***窗体中的 MaskedTextBox【英文标题】:Windows Forms: Unable to Click to Focus a MaskedTextBox in a Non TopLevel Form 【发布时间】:2011-02-21 22:28:10 【问题描述】:

正如标题所说,我有一个 Child 表单,它的 TopLevel 属性设置为 False,我无法单击它包含的 MaskedTextBox 控件(以便将焦点集中在它上面)。不过,我可以通过在键盘上使用 TAB 来集中注意力。

子窗体包含其他常规 TextBox 控件,我可以毫无问题地单击这些控件来聚焦,尽管它们也表现出一些奇怪的行为:例如,如果我在 Textbox 中有一个值,我尝试从字符串的结尾到开头,什么也没有发生。事实上,我根本无法使用鼠标在 TextBox 的文本中移动光标(尽管它们可以使用键盘箭头键)。

我不太担心奇怪的 TextBox 行为,但为什么我不能通过单击来激活我的 MaskedTextBox?

下面是显示表单的代码:

Dim newReportForm As New Form
Dim formName As String
Dim FullTypeName As String
Dim FormInstanceType As Type

formName = TreeView1.SelectedNode.Name

FullTypeName = Application.ProductName & "." & formName

FormInstanceType = Type.GetType(FullTypeName, True, True)

newReportForm = CType(Activator.CreateInstance(FormInstanceType), Form)
Try
   newReportForm.Top = CType(SplitContainer1.Panel2.Controls(0), Form).Top + 25
   newReportForm.Left = CType(SplitContainer1.Panel2.Controls(0), Form).Left + 25
Catch
End Try
newReportForm.TopLevel = False
newReportForm.Parent = SplitContainer1.Panel2
newReportForm.BringToFront()                
newReportForm.Show()

【问题讨论】:

【参考方案1】:

我尝试了你的代码,这次得到了很好的重现。正如我在原帖中提到的,这确实是一个窗口激活问题。您可以在 Spy++ 中看到这一点,注意 WM_MOUSEACTIVATE 消息。

这是因为您显示带有标题栏的表单。这使 Windows 窗口管理器相信该窗口可以被激活。这实际上不起作用,它不再是***窗口。从标题栏中可见,它永远不会使用“窗口激活”颜色绘制。

您必须从表单中删除标题栏。最好将此行添加到您的代码中:

    newReportForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None

这会将表单转换为与 UserControl 无法区分的控件。您仍然可以使用以下代码使其与众不同:

    newReportForm.ControlBox = False
    newReportForm.Text = ""

两种方法都可以解决鼠标点击问题。

【讨论】:

你是对的,这两个建议都解决了这个问题。然而,它以我们不想要的方式显示表单。实际上,我们要做的是在 SplitContainer 的面板中显示此表单(modelessley)(这样表单就不能拖动到此 splitcontainer 面板之外)。在这一点上,我相当肯定我们的做法是错误的,我们需要调整我们显示表单的方式。非常感谢您的帮助。【参考方案2】:

这是一个悲惨的错误,我花了很长时间才找到这个问题。我们正在做与 OP 完全相同的事情,在拆分容器中显示一个 Form。我的解决方法是为 MaskedTextBox 的 Click 事件添加一个事件处理程序:

    private void MaskedTextBoxSetFocus(object sender, EventArgs e)
    
        var mtb = (MaskedTextBox)sender;
        mtb.Focus();
    

这适用于 MaskedTextBox,但我担心由于这个错误导致的其他奇怪行为,所以我可能会按照接受的答案设置边框样式。

【讨论】:

我们正在做与解决方法完全相同的事情。但是,我相信您已经注意到,当您聚焦时,您无法选择将光标定位在哪个字符上。因此,每次单击时它都会转到最后一个已知位置。如果您尝试单击输入文本的不同部分,这很烦人。【参考方案3】:

文本框行为是同一问题的症状。某些东西正在吞噬鼠标按下通知。您的代码 sn-p 没有解释它。表单确实会吞噬激活它们的鼠标单击,但这是一次性行为,通过将其 TopLevel 属性设置为 False 会关闭。

剩下的不多了。一个候选者是 Control.Capture 属性,该属性在按钮的 MouseDown 事件中打开,这样无论鼠标移动到哪里,按钮都可以看到 MouseUp 事件。这也是一次性的效果。注意在 MouseDown 事件中设置焦点的控件。

另一个是表单中的某种 IMessageFilter 代码,它正在吃 WM_LBUTTONDOWN 消息。

【讨论】:

感谢汉斯的洞察力。我可以贡献我将 TopLevel 设置为 True,并且不再存在奇怪的行为。我还没有找到任何可能吞下事件、使用 Control.Capture 属性或任何 IMessageFilter 代码的 Handlers 的致命赠品。不幸的是,我没有为 Parent 表单编写代码,所以我可能会遗漏一些东西。如果我发布父表单的其余代码会有帮助吗?大约 300 行。 值得怀疑。使用 Spy++ 查看点击的去向。 看起来点击一直到父表单。我不是 100% 确定我在寻找什么,但是单击蒙面文本框时触发的事件似乎都与单击常规文本框时触发的事件相匹配(确实正确获得焦点)。

以上是关于Windows 窗体:无法单击以聚焦非***窗体中的 MaskedTextBox的主要内容,如果未能解决你的问题,请参考以下文章

C# Windows 窗体无法在 Windows10 上加载非托管 C++ DLL

如何在windows窗体里面添加窗口

c#如何单击按钮显示另一个窗体

C#如何在 Windows 窗体应用程序中使用事件

如何在 Windows 窗体中分离 UI 线程和进程线程

c#如何实现关闭当前窗体并打开另一个已经创建的窗体。