Заголовок ListView на самом деле является другим объектом, его имя класса SysHeader32
.
Заголовок отображается в подробном представлении, но он создается вместе с ListView, поэтому он есть, даже если вы его не видите (если Вы добавили хотя бы одну колонку, то есть).
Это не управляемый дочерний элемент управления ListView: коллекция ListView.Controls
обычно пуста.
Но это дочерний элемент управления SysListView32
, из которого происходит управляемый класс, таким образом, вы может получить его дескриптор и прочитать его сообщения; сообщение WM_MOUSELEAVE
, в данном случае.
- Мы можем получить его дескриптор, используя FindWinDowEx или SendMessage (с
LVM_GETHEADER
), назначить дескриптор для * 1023 Класс * NativeWindow переопределяет его WndProc
и , перехватывает сообщения, которые мы должны обработать. В WM_MOUSELEAVE
класс NativeWindow
вызывает событие, на которое может подписаться родительский ListView, в результате чего возникает собственное событие MouseLeave
.
Поскольку, как описано, заголовок является отдельным объектом, 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