Rubrik: | VB-Versionen: VB2005, VB2008 | 02.06.09 |
Rechtsklick auf Spaltenbezeichner im ListView abfangen Das ListView-Control bietet leider kein Möglichkeit, gezielt auf einen Rechtsklick innerhalb der Spaltenbezeichner zu reagieren. Diese Tipp schafft Abhilfe! | ||
Autor: Dieter Otter | Bewertung: | Views: 1.655 |
http://www.tools4vb.de/ | System: Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt |
Wie man auf einen Rechtsklick innerhalb der ListView-Elemente reagieren kann, haben wir Ihnen bereits gezeigt.
Was aber, wenn man den Rechtsklick auf einen Spaltenbezeichner abfragen will? Hierfür bietet uns das ListView-Control leider keine Möglichkeit, gezielt darauf zu reagieren. Das ListView löst lediglich beim Linksklick auf einer der Spaltenbezeichner (ColumnHeader) ein entsprechendes Event aus. Ein Rechtsklick hingegen bleibt ungeahntet.
Mit diesem Extra-Tipp zeigen wir eine Möglichkeit auf, wie man dennoch auf einen Rechtsklick reagieren kann.
Der Trick:
Der Trick besteht darin, das wir dem ListView ein Kontextmenü hinzufügen. Klickt der User nun mit der rechten Maustaste in das ListView (es spielt hierbei keine Rolle, ob der Rechtsklick im
ColumnHeader-Bereich oder ListViewItem-Bereich erfolgt), wird das Opening-Event des ContextMenuStrip-Objekts ausgelöst. Durch Setzen des Parameters "Cancel" kann die Anzeige des
Kontextmenüs unterdrückt werden. Jetzt müssen wir nur noch herausfinden, ob der Mausklick innerhalb der Spaltenbezeichner erfolgte.
Hierzu müssen wir zunächst das Rechteck der ColumnHeader-Leiste ermitteln. Dann brauchen wir einfach nur abzufragen, ob sich der Mauszeiger innerhalb des ermittelten Rechtecks befindet.
Das Ganze sieht wie folgt aus: Fügen Sie nachfolgende Klasse in Ihr Projekt ein.
Imports System.Runtime.InteropServices Public Class lvColumnHeaderRect
' benötigte API-Funktionen, um das Handle der ColumnHeader zu ermitteln Private Delegate Function WinCallBack( _ ByVal hWnd As IntPtr, _ ByVal lParam As IntPtr) As Boolean <DllImport("user32.Dll")> _ Private Shared Function EnumChildWindows(ByVal hWndParent As IntPtr, _ ByVal callBackFunc As WinCallBack, _ ByVal lParam As IntPtr) As Integer End Function <DllImport("user32.dll")> _ Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, _ ByRef lpRect As RECT) As Integer End Function <StructLayout(LayoutKind.Sequential)> _ Private Structure RECT Public Left As Integer Public Top As Integer Public Right As Integer Public Bottom As Integer End Structure
' private Eigenschaften Private _headerRect As Rectangle = Rectangle.Empty Private _columns() As ColumnHeader
' Unsere CallBack-Funktion zum Ermitteln des Handles der ColumnHeader-Leiste Private Function lvCallBack(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean Dim r As RECT If GetWindowRect(hWnd, r) <> 0 Then _headerRect = New Rectangle(r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top) End If Return False End Function
''' <summary> ''' Initialisiert die Klasse mit dem angegebenen ListView-Objekt ''' </summary> ''' <param name="ListView">ListView-Objekt</param> Public Sub New(ByVal ListView As ListView) ' Handle der ColumnHeader-Leiste ermitteln EnumChildWindows(ListView.Handle.ToInt32, _ New WinCallBack(AddressOf lvCallBack), IntPtr.Zero) ' ColumnHeader-Objekte in der angezeigten Reihenfolge ReDim _columns(ListView.Columns.Count) For Each column As ColumnHeader In ListView.Columns _columns(column.DisplayIndex) = column Next End Sub
''' <summary> ''' Gibt das Rechteck der ColumnHeader-Leiste zurück ''' </summary> Public ReadOnly Property Rectangle() As Rectangle Get Return _headerRect End Get End Property
''' <summary> ''' Ermittelt die Spalte (das ColumnHeader-Objekt) unter dem Mauszeiger ''' </summary> ''' <param name="p">Position des Mauszeigers</param> ''' <value></value> Public ReadOnly Property ColumnHeader(ByVal p As Point) As ColumnHeader Get Dim x As Integer = _headerRect.X For Each column As ColumnHeader In _columns x += column.Width If p.X <= x Then Return column End If Next Return Nothing End Get End Property
End Class
So... und jetzt noch folgender Code in der Form, auf der sich das ListView befindet:
' Hilfs-Kontextmenü Dim WithEvents lvMenu As New ContextMenuStrip
' Bei Rechtsklick will VB das Kontextmenü anzeigen Private Sub lvMenu_Opening(ByVal sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles lvMenu.Opening ' Anzeige des Kontextmenüs unterbinden e.Cancel = True ' ColumnHeader-Rechteck ermitteln With New lvColumnHeaderRect(ListView1) ' Prüfen, ob sich die Maus in der Headerzeile befindet If .Rectangle.Contains(Control.MousePosition) Then ' Rechtsklick in den ColumnHeader-Bereich ' ggf. Spalte ermitteln Dim column As ColumnHeader = .ColumnHeader(Control.MousePosition) If Not IsNothing(column) Then MsgBox("Rechtsklick auf Spalte '" & column.Text & "'") End If End If End With End Sub