Listview MouseLeave 事件:不包括 Header
Listview MouseLeave event: the Header is not included
我已经订阅了我的 ListView 的 MouseLeave 事件。当鼠标指针离开 ListView 边界时应引发该事件。
这有效,但是当鼠标指针进入 ListView 的 Header 然后离开 ListView 边界时,不会引发该事件。
Private Sub LV1_test_MouseLeave(sender As Object, e As EventArgs) Handles LV1_test.MouseLeave
// Not raised when the Pointer leaves the premises from the top of the ListView
End Sub
我能做什么?
ListViewHeader实际上是一个不同的object,它的class名字是SysHeader32
.
Header 显示在 Details View 中,但它是与 ListView 一起创建的,因此即使您看不到它(如果您至少添加了一个 Column),它也在那里。
它不是 ListView 的托管 child 控件:ListView.Controls
collection 通常是空的。
但它是 SysListView32
本机控件的 child 控件,托管 class 从中派生,因此,您可以获得它的句柄并 读取 它的消息; WM_MOUSELEAVE
消息,在这种情况下。
- 我们可以使用 FindWinDowEx or SendMessage (with
LVM_GETHEADER
), assign the handle to a NativeWindow class 获取它的句柄,覆盖它的 WndProc
并 拦截 我们需要处理的消息。在 WM_MOUSELEAVE
上,NativeWindow
class 引发了 parent ListView 可以订阅的事件,引发了它自己的 MouseLeave
事件结果。
因为如上所述,Header 是一个不同的 object,当鼠标指针移动到其 Header 上时,ListView 会生成一个 MouseLeave
事件。我们需要覆盖此行为,因此仅当鼠标指针完全离开 ListView 边界时才会引发 MouseLeave
事件。
- 我们可以覆盖
OnMouseLeave
,验证 MousePosition 返回的位置(转换为客户端度量)是否在 ListView 客户端范围内,并让该方法仅引发 MouseLeave
事件当它没有时。
编辑:
添加了 WM_PARENTNOTIFY
message check (for the WM_CREATE
事件通知)以处理 run-time 处的 Header 创建。
自定义 ListView 控件:
现在,如果您订阅此自定义控件的 MouseLeave
事件,则无论 Cursor 位于何处,只有当鼠标指针离开 ListView 的客户区时才会引发该事件。
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
<DesignerCategory("Code")>
Class ListViewCustom
Inherits ListView
Private Const LVM_GETHEADER As Integer = &H1000 + 31
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function SendMessage(hWnd As IntPtr, uMsg As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
End Function
Private sysHeader As SysHeader32 = Nothing
Private Sub AddSysHeaderHandler()
If DesignMode Then Return
If sysHeader Is Nothing Then
Dim sysHeaderHwnd = SendMessage(Me.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero)
If sysHeaderHwnd <> IntPtr.Zero Then
sysHeader = New SysHeader32(sysHeaderHwnd)
AddHandler sysHeader.SysHeaderMouseLeave,
Sub(s, evt)
Me.OnMouseLeave(evt)
End Sub
End If
End If
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
AddSysHeaderHandler()
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
If Not Me.ClientRectangle.Contains(PointToClient(MousePosition)) Then
MyBase.OnMouseLeave(e)
End If
End Sub
' Handles the Header creation at run-time
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case &H210 'WM_PARENTNOTIFY
Dim msg As Integer = m.WParam.ToInt32() And &HFFFF
Select Case msg
Case &H1 ' WM_CREATE
AddSysHeaderHandler()
End Select
End Select
MyBase.WndProc(m)
End Sub
Protected Overrides Sub Dispose(disposing As Boolean)
If (disposing) Then sysHeader?.ReleaseHandle()
MyBase.Dispose(disposing)
End Sub
Private Class SysHeader32
Inherits NativeWindow
Public Event SysHeaderMouseLeave As EventHandler(Of EventArgs)
Public Sub New(handle As IntPtr)
AssignHandle(handle)
End Sub
Protected Friend Overridable Sub OnSysHeaderMouseLeave(e As EventArgs)
RaiseEvent SysHeaderMouseLeave(Me, e)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case &H2A3 'WM_MOUSELEAVE
OnSysHeaderMouseLeave(EventArgs.Empty)
m.Result = IntPtr.Zero
Exit Select
Case Else
' NOP: Log other messages, add more cases...
End Select
MyBase.WndProc(m)
End Sub
End Class
End Class
我已经订阅了我的 ListView 的 MouseLeave 事件。当鼠标指针离开 ListView 边界时应引发该事件。
这有效,但是当鼠标指针进入 ListView 的 Header 然后离开 ListView 边界时,不会引发该事件。
Private Sub LV1_test_MouseLeave(sender As Object, e As EventArgs) Handles LV1_test.MouseLeave
// Not raised when the Pointer leaves the premises from the top of the ListView
End Sub
我能做什么?
ListViewHeader实际上是一个不同的object,它的class名字是SysHeader32
.
Header 显示在 Details View 中,但它是与 ListView 一起创建的,因此即使您看不到它(如果您至少添加了一个 Column),它也在那里。
它不是 ListView 的托管 child 控件:ListView.Controls
collection 通常是空的。
但它是 SysListView32
本机控件的 child 控件,托管 class 从中派生,因此,您可以获得它的句柄并 读取 它的消息; WM_MOUSELEAVE
消息,在这种情况下。
- 我们可以使用 FindWinDowEx or SendMessage (with
LVM_GETHEADER
), assign the handle to a NativeWindow class 获取它的句柄,覆盖它的WndProc
并 拦截 我们需要处理的消息。在WM_MOUSELEAVE
上,NativeWindow
class 引发了 parent ListView 可以订阅的事件,引发了它自己的MouseLeave
事件结果。
因为如上所述,Header 是一个不同的 object,当鼠标指针移动到其 Header 上时,ListView 会生成一个 MouseLeave
事件。我们需要覆盖此行为,因此仅当鼠标指针完全离开 ListView 边界时才会引发 MouseLeave
事件。
- 我们可以覆盖
OnMouseLeave
,验证 MousePosition 返回的位置(转换为客户端度量)是否在 ListView 客户端范围内,并让该方法仅引发MouseLeave
事件当它没有时。
编辑:
添加了 WM_PARENTNOTIFY
message check (for the WM_CREATE
事件通知)以处理 run-time 处的 Header 创建。
自定义 ListView 控件:
现在,如果您订阅此自定义控件的 MouseLeave
事件,则无论 Cursor 位于何处,只有当鼠标指针离开 ListView 的客户区时才会引发该事件。
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
<DesignerCategory("Code")>
Class ListViewCustom
Inherits ListView
Private Const LVM_GETHEADER As Integer = &H1000 + 31
<DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
Friend Shared Function SendMessage(hWnd As IntPtr, uMsg As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
End Function
Private sysHeader As SysHeader32 = Nothing
Private Sub AddSysHeaderHandler()
If DesignMode Then Return
If sysHeader Is Nothing Then
Dim sysHeaderHwnd = SendMessage(Me.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero)
If sysHeaderHwnd <> IntPtr.Zero Then
sysHeader = New SysHeader32(sysHeaderHwnd)
AddHandler sysHeader.SysHeaderMouseLeave,
Sub(s, evt)
Me.OnMouseLeave(evt)
End Sub
End If
End If
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
AddSysHeaderHandler()
End Sub
Protected Overrides Sub OnMouseLeave(e As EventArgs)
If Not Me.ClientRectangle.Contains(PointToClient(MousePosition)) Then
MyBase.OnMouseLeave(e)
End If
End Sub
' Handles the Header creation at run-time
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case &H210 'WM_PARENTNOTIFY
Dim msg As Integer = m.WParam.ToInt32() And &HFFFF
Select Case msg
Case &H1 ' WM_CREATE
AddSysHeaderHandler()
End Select
End Select
MyBase.WndProc(m)
End Sub
Protected Overrides Sub Dispose(disposing As Boolean)
If (disposing) Then sysHeader?.ReleaseHandle()
MyBase.Dispose(disposing)
End Sub
Private Class SysHeader32
Inherits NativeWindow
Public Event SysHeaderMouseLeave As EventHandler(Of EventArgs)
Public Sub New(handle As IntPtr)
AssignHandle(handle)
End Sub
Protected Friend Overridable Sub OnSysHeaderMouseLeave(e As EventArgs)
RaiseEvent SysHeaderMouseLeave(Me, e)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case &H2A3 'WM_MOUSELEAVE
OnSysHeaderMouseLeave(EventArgs.Empty)
m.Result = IntPtr.Zero
Exit Select
Case Else
' NOP: Log other messages, add more cases...
End Select
MyBase.WndProc(m)
End Sub
End Class
End Class