我制作了一个自定义的ComboBox,当用户点击外部时,我很难让它的下拉菜单(Panel)关闭。正如大家可能都知道的那样,使用LostFocus
事件是不够的,因为当用户点击例如:scroolbar或表单本身时,控件不会失去焦点。我尝试使用IMessageFilter
,但我不认为我理解它是如何工作的。我还尝试使用Capture
属性,强制下拉列表捕获鼠标,但这也强制鼠标单击在下拉列表(Panel)本身上发生,这意味着如果用户点击了下拉列表中的项目,点击不会起作用。
让我澄清一下:
我正在创建一个自定义控件,一个UserControl,它被编译为.DLL,并且可以从工具箱中拖放到表单上,就像任何其他Winforms控件一样。 该控件是Combobox。 我想让用户在其外部点击时关闭Combobox的下拉列表(这是一个在运行时创建的面板),就像普通的ComboBox一样。 问题是什么?检测面板外部的点击,然后关闭它。
- >使用LostFocus
事件:还不够。如果用户单击表单上的空白区域,则不会触发LostFocus
。我知道我可以在表单上放置LostFocus
事件并将ActiveContrl
设置为Nothing
,但这需要我的自定义ComboBox的用户(开发人员)在每个表单上放置相同的代码他们使用控件。
- >使用Capture
属性:到目前为止已经取得了最好的结果。但仍有一些问题。当Capture
设置为True
时,鼠标确实被控件捕获,该控件将该属性设置为True。因此,应用程序上的任何其他控件都不会感测到鼠标活动,而只会捕获捕获鼠标的控件。它只会在用户执行单击时释放鼠标。这会导致一些问题:
Button
),并且下拉列表(Panel
)的Capture
属性设置为true,则点击将为& #34;忽略",因为它将由下拉列表处理,而不是由用户实际想要点击的Button
处理。Button
(ComboBox' s项目)上方时,它们不会突出显示,因为没有为它们触发MouseEnter
,因为鼠标是被下拉捕获。有一种方法可以解决第一个问题:您可以使用Control.MousePosition
找到鼠标指向哪个按钮,然后强行单击它。
虽然我还没有找到解决第二和第三期问题的方法。我想到的一个可能的解决方案是当鼠标进入时将下拉列表的Capture
属性设置为False。所以,这就是它的工作原理:
但是当我尝试这样做时,又出现了另一个问题:当控件将其Capture
属性设置为True时,它会不断触发MouseEnter
个事件。 MouseEnter
事件未使用真正的鼠标指针位置。即使鼠标指针实际位于Control之外,如果其Capture
属性设置为True,该控件也会认为鼠标实际位于其中。
答案 0 :(得分:1)
Edit2:这是处理一些不同类型事件的代码(现在应该适用于所有情况)。
Public Class Form1
Private Shared mouseNotify() As Int32 = {&H201, &H204, &H207} ' WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN
Private Shared scrollNotify() As Int32 = {&H114, &H115} ' WM_HSCROLL, WM_VSCROLL
Private Shared scrollCommands() As Int32 = {0, 1, 2, 3, 4, 5} ' SB_LINEUP, SB_LINEDOWN, SB_PAGEUP, SB_PAGEDOWN, SB_THUMBTRACK, SB_THUMBPOSITION
Private Sub baseLoad(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
AutoScroll = True
Controls.Add(myPanel)
Controls.Add(myTextBox4)
myPanel.myTextBox1.Focus()
End Sub
Private myTextBox4 As New customTextBox(300)
Private myPanel As New customPanel
Protected Overrides Sub OnScroll(ByVal se As ScrollEventArgs)
MyBase.OnScroll(se)
ActiveControl = Nothing
End Sub
Protected Overrides Sub OnMouseWheel(ByVal e As MouseEventArgs)
MyBase.OnMouseWheel(e)
ActiveControl = Nothing
End Sub
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
ActiveControl = Nothing
End Sub
Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
MyBase.OnMove(e)
ActiveControl = Nothing
End Sub
Friend Shared Function isOverControl(ByRef theControl As Control) As Boolean
Return theControl.ClientRectangle.Contains(theControl.PointToClient(Cursor.Position))
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
If mouseNotify.Contains(CInt(m.Msg)) Then
If Not isOverControl(myPanel) Then
ActiveControl = Nothing
Else
myPanel.myTextBox1.Focus()
End If
End If
MyBase.WndProc(m)
End Sub
Friend Class customPanel : Inherits Panel
Friend myTextBox1 As New customTextBox(20)
Private myTextBox2 As New customTextBox(60)
Private myTextBox3 As New customTextBox(200)
Friend Sub New()
AutoScroll = True
Location = New Point(0, 100)
Size = New Size(200, 100)
Controls.Add(myTextBox1)
Controls.Add(myTextBox2)
Controls.Add(myTextBox3)
End Sub
Protected Overrides Sub OnLeave(ByVal e As EventArgs)
MyBase.OnLeave(e)
myTextBox1.Text = "false"
myTextBox2.Text = "false"
BackColor = Color.Green
End Sub
Protected Overrides Sub OnEnter(ByVal e As EventArgs)
myTextBox1.Text = "true"
myTextBox2.Text = "true"
BackColor = Color.Gold
MyBase.OnEnter(e)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If mouseNotify.Contains(CInt(m.Msg)) Then
If isOverControl(Me) Then Form1.WndProc(m)
End If
MyBase.WndProc(m)
End Sub
End Class
Friend Class customTextBox : Inherits TextBox
Friend Sub New(ByVal y As Integer)
Location = New Point(10, y)
Size = New Size(100, 30)
End Sub
Protected Overrides Sub OnLeave(ByVal e As EventArgs)
MyBase.OnLeave(e)
BackColor = Color.Blue
End Sub
Protected Overrides Sub OnEnter(ByVal e As EventArgs)
BackColor = Color.Red
MyBase.OnEnter(e)
End Sub
End Class
End Class
如果它在所有情况下都不起作用,您可能必须将事件附加到表单上的所有控件上,这些控件无法获得对鼠标事件的关注。
另外,根据控件的类型,这种方式略有不同。 richtextbox例如使用OnHScroll和OnVscroll,而不是OnScroll。你也可以通过CInt(m.WParam.ToInt32>> 16)获得拇指位置,仅对SB_THUMBTRACK,SB_THUMBPOSITION有效。
另外,这里有一些有趣的技巧:Handling a click event anywhere inside a panel in C#
这实际上取自WndProc的MSDN页面:http://msdn.microsoft.com/en-us/library/system.windows.forms.control.wndproc%28v=vs.110%29.aspx
和NativeWindow类的页面:http://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow.aspx