ListView:用鼠标拖动的MultiSelect项 [英] ListView: MultiSelect items with mouse drag

查看:201
本文介绍了ListView:用鼠标拖动的MultiSelect项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆