ListView:用鼠标拖动的MultiSelect项 [英] ListView: MultiSelect items with mouse drag
问题描述
在ListView中,我可以按 Ctrl + Shift 并单击要选择的项目.但是,我想拖动鼠标来选择项目(如DataGridView).我尝试了下面的代码,但遇到了这样的问题:
In ListView, I can press Ctrl + Shift and click on the item to select. But, I want to drag the mouse to select the items (like DataGridView). I tried this code (below) and I had a problem like this:
我的代码:
Private mouseDownLV As Boolean
Private Sub ListView1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDown
mouseDownLV = True
End Sub
Private Sub ListView1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseMove
If mouseDownLV Then
Try
Dim i = ListView1.HitTest(e.Location).Item.Index
ListView1.Items(i).Selected = True
Catch ' ex As Exception
End Try
End If
End Sub
Private Sub ListView1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseUp
mouseDownLV = False
End Sub
推荐答案
实际上,您需要遍历当前显示的ListViewItem
对象和 toggle 与之相交的项目的Selected
属性鼠标移动.这是实现该目标的一种方法:
Actually you need to iterate through the currently displayed ListViewItem
objects and toggle the Selected
property of the items that intersect with the mouse movement. Here's a way to achieve that:
声明一个名为startPoint
的类成员:
Declare a class member named startPoint
:
Private startPoint As Point
处理MouseDown
事件以设置起始位置:
Handle the MouseDown
event to set the starting position:
Private Sub ListView1_MouseDown(sender As Object, e As MouseEventArgs) Handles ListView1.MouseDown
Dim s = DirectCast(sender, ListView)
If e.Button = MouseButtons.Left AndAlso
s.Items.Count > 1 Then
startPoint = e.Location
End If
End Sub
处理MouseMove
事件以切换 Selected
属性:
Private Sub ListView1_MouseMove(sender As Object, e As MouseEventArgs) Handles ListView1.MouseMove
Dim s = DirectCast(sender, ListView)
If e.Button = MouseButtons.Left AndAlso s.Items.Count > 1 Then
Dim selRect As New Rectangle(Math.Min(startPoint.X, e.Location.X),
Math.Min(startPoint.Y, e.Location.Y),
Math.Abs(e.Location.X - startPoint.X),
Math.Abs(e.Location.Y - startPoint.Y))
Dim cr = s.ClientRectangle
'Toggle selection...
For Each item In s.Items.Cast(Of ListViewItem).
Where(Function(x) x.Bounds.IntersectsWith(cr))
item.Selected = selRect.IntersectsWith(item.Bounds)
Next
End If
End Sub
一个快速演示,以检查以下内容:
A quick demo to check that:
但是,如果您有很多项目的工作区的大小不足以显示全部内容,因此可以看到垂直滚动条,该怎么办?您将获得如下内容:
But what if you have many items where the size of the client area is not large enough to display them all and thus the vertical scrollbar is visible? You will get something like this:
如您所见,垂直滚动条不会移动,您将无法继续选择/取消选择隐藏的项目.要解决此问题,我们需要更多代码:
As you can see, the vertical scrollbar does not move and you won't be able to continue selecting/deselecting the hidden items. To fix that, we need some more code:
导入 GetScrollPos 在您的班级某处起作用:
Import the signature of the GetScrollPos function somewhere in your class:
Imports System.Runtime.InteropServices
'...
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Shared Function GetScrollPos(hWnd As IntPtr,
nBar As Orientation) As Integer
End Function
注意::传递System.Windows.Forms.Orientation
值而不是Interger
.
Note: Passing a System.Windows.Forms.Orientation
value instead of an Interger
.
将MouseDown
事件更改为:
Private Sub ListView1_MouseDown(sender As Object, e As MouseEventArgs) Handles ListView1.MouseDown
Dim s = DirectCast(sender, ListView)
If e.Button = MouseButtons.Left AndAlso
s.Items.Count > 1 Then
Dim vsp = GetScrollPos(s.Handle, Orientation.Vertical)
Dim yOffset = s.Font.Height * vsp
startPoint = New Point(e.X, e.Y + yOffset)
End If
End Sub
和MouseMove
事件发生:
Private Sub ListView1_MouseMove(sender As Object, e As MouseEventArgs) Handles ListView1.MouseMove
Dim s = DirectCast(sender, ListView)
If e.Button = MouseButtons.Left AndAlso s.Items.Count > 1 Then
Dim vsp = GetScrollPos(s.Handle, Orientation.Vertical)
Dim yOffset = s.Font.Height * vsp
Dim selRect As New Rectangle(Math.Min(startPoint.X, e.Location.X),
Math.Min(startPoint.Y - yOffset, e.Location.Y),
Math.Abs(e.Location.X - startPoint.X),
Math.Abs(e.Location.Y - startPoint.Y + yOffset))
Dim cr = s.ClientRectangle
'Toggle selection...
For Each item In s.Items.Cast(Of ListViewItem).
Where(Function(x) x.Bounds.IntersectsWith(cr))
item.Selected = selRect.IntersectsWith(item.Bounds)
Next
'Scroll if needed...
Dim p = s.PointToClient(Cursor.Position)
Dim lvi = s.GetItemAt(p.X, p.Y)
If lvi Is Nothing Then Return
Dim fh = s.Font.Height
If lvi.Index > 0 AndAlso (p.Y - lvi.Bounds.Height * 1.5) <= fh Then
s.Items(lvi.Index - 1).EnsureVisible()
ElseIf lvi.Index < s.Items.Count - 1 AndAlso
(p.Y + lvi.Bounds.Height * 1.5) > (s.Height - fh) Then
s.Items(lvi.Index + 1).EnsureVisible()
End If
End If
End Sub
结果是:
此处是针对此问题的VB.NET自定义ListView控件,并且
Here is VB.NET custom ListView control for this problem, and another in C#.
这篇关于ListView:用鼠标拖动的MultiSelect项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!