[英]Close panel if clicked outside
我正在制作一个自定义的ComboBox,当用户单击外部时,我正在努力使其下拉菜单(面板)关闭。 众所周知,使用LostFocus
事件是不够的,因为当用户单击例如scroolbar或表单本身时,控件不会失去焦点。 我尝试使用IMessageFilter
,但是我认为我不了解它是如何工作的。 我还尝试使用Capture
属性,强制下拉菜单捕获鼠标,但这也迫使鼠标在下拉菜单(Panel)本身上发生单击,这意味着如果用户单击了下拉菜单中的项目,则单击会获胜不行
让我澄清一下:
我正在制作一个自定义控件,即UserControl,它已编译为.DLL,并且可以像其他Winforms控件一样从Toolbox拖放到窗体上。 该控件是一个组合框。 我想使Combobox的下拉菜单(这是一个在运行时创建的面板)在用户单击它时关闭,就像普通的ComboBox一样。 那是什么问题呢? 检测面板外部的点击,然后将其关闭。
->使用LostFocus
事件:不够。 如果用户单击表单上的空白,则不会触发LostFocus
。 我知道我可以在表单上放置一个LostFocus
事件并将ActiveContrl
设置为Nothing
,但这将要求我自定义ComboBox的用户(开发人员)在使用控件的每种表单上放置相同的代码。
->使用Capture
属性:到目前为止,已获得最佳结果。 但是仍然存在一些问题。 当Capture
设置为True
,将属性设置为True的控件确实捕获了鼠标。 因此,应用程序上的任何其他控件都不会检测到鼠标活动,只有捕获了鼠标的控件才能检测到。 仅在用户单击时释放鼠标。 这会导致一些问题:
Button
),并且下拉菜单( Panel
)的Capture
属性设置为true,则单击将被“忽略”,因为它将由下拉菜单处理,而不是在Button
上,用户其实是想点击。 Button
上方时,它们不会突出显示,因为没有为它们触发MouseEnter
,因为鼠标被下拉菜单捕获了。 有一种方法可以解决第一个问题:使用Control.MousePosition
可以找到鼠标指向哪个按钮,然后强制单击它。 但是,我还没有找到解决第二个和第三个问题的方法。 我想到的一种可能的解决方案是,当鼠标进入下拉菜单时将其Capture
属性设置为False。 因此,这是它的工作方式:
但是,当我尝试执行此操作时,又出现了另一个问题:当控件的Capture
属性设置为True时,它将不断触发MouseEnter
事件。 MouseEnter
事件不使用真实的鼠标指针位置。 即使鼠标指针实际上位于控件外部,但如果其Capture
属性设置为True,则该控件也会认为鼠标实际上位于控件内部。
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有效。
另外,这里还有一些有趣的技术: 在C#面板内的任何地方处理click事件
这实际上是从WndProc的MSDN页面上获取的: http : //msdn.microsoft.com/en-us/library/system.windows.forms.control.wndproc%28v=vs.110%29.aspx
以及NativeWindow类的页面: http : //msdn.microsoft.com/zh-cn/library/system.windows.forms.nativewindow.aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.