ListView Header其实是一个不同的对象,它的类名是SysHeader32。
Header 显示在 Details View 中,但它是与 ListView 一起创建的,因此即使您看不到它(如果您至少添加了一个 Column),它也存在。
它不是 ListView 的托管子控件:ListView.Controls 集合通常为空。
但它是托管类派生自的SysListView32 本机控件的子控件,因此,您可以获取它的句柄并读取它的消息; WM_MOUSELEAVE 消息,在这种情况下。
如上所述,由于 Header 是一个不同的对象,当鼠标指针移到其 Header 上时,ListView 会生成一个MouseLeave 事件。我们需要重写这个行为,所以MouseLeave 事件只有在鼠标指针完全离开 ListView 边界时才会触发。
- 我们可以覆盖
OnMouseLeave,验证MousePosition(转换为客户端度量)返回的位置是否在ListView客户端范围内,并让该方法仅在没有时引发MouseLeave事件。
编辑:
添加了WM_PARENTNOTIFY 消息检查(用于WM_CREATE 事件通知)以在运行时处理标头创建。
自定义 ListView 控件:
现在,如果您订阅此自定义控件的MouseLeave 事件,则该事件仅在鼠标指针离开 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