【问题标题】:Count Number of Times a Mouse Wheel Scroll Event has Occurred计数鼠标滚轮滚动事件发生的次数
【发布时间】:2026-02-11 07:25:01
【问题描述】:

现在,MouseWheel 滚动更改了我的 DGV 中可查看的记录。负 iDelta 移至下一条记录,正 iDelta 移至上一条记录。每条记录都包含一个页眉/页脚和 dgv 中的实际数据。

我正在尝试优化滚动浏览记录的速度。在我开始修改它之前,代码会加载每个页眉/页脚,然后在每次检测到 MouseWheel 事件时加载记录的整个 dgv。

我正在尝试将其更改为仅加载页眉/页脚的位置,直到用户暂停(例如约 500 毫秒)。这将确保不会加载不必要的 dgv,从而浪费时间。

我真的一直在努力寻找一种方法来计算滚轮被滚动的次数,一种检测用户是否有一段时间没有滚动鼠标滚轮的方法,或者一种调用方法鼠标滚轮滚动子例程,而仍在当前鼠标滚轮滚动子例程中。我认为任何这些都会让我走上成功之路。这是我到目前为止所拥有的。显然,它不能按我的意愿工作。

Private Sub SplitContainer1_MouseWheel(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles SplitContainer1.MouseWheel

    Dim iDelta As Integer = e.Delta

    ' Limit the times the stopwatch restarts to every 500ms interval
    If numberOfScrolls = 0 Then
        mouseScrollStopWatch.Start()
    End If

    Select Case iButton
        Case 1, 2
            ' If iDelta is negative move to 'next' record
            If iDelta < 0 Then   

                ' If 500 ms has passed since the 'first' scroll event
                If mouseScrollStopWatch.ElapsedMilliseconds > 500 Then

                    ' Loads the header and footer of the 'next' record  
                    BindPartNumMoveNext() 

                    ' Update the dgv  
                    updateDGV()      

                   ' Reset the stopwatch            
                    mouseScrollStopWatch.Reset()

                   ' Reset number of Scrolls
                    numberOfScrolls = 0                                 

               ' If 500ms has not passed since the 'first' scroll event
                Else

                    ' Loads header and footer                           
                    BindPartNumMoveNext()  

                    ' sets number of scrolls to anything but 0     
                    numberOfScrolls = 1                                 
                End If

            ' If iDelta is positive move to 'previous' record
            Else           

                ' If 500 ms has passed since the 'first' scroll event                         
                If mouseScrollStopWatch.ElapsedMilliseconds > 500 Then 

                    ' Loads the header and footer of the 'previous' record
                    BindPartNumMovePrevious()    

                    ' Update the dgv
                    updateDGV()                  

                    ' Reset the stopwatch
                    mouseScrollStopWatch.Reset()                        

                    ' Reset number of Scrolls
                    numberOfScrolls = 0    

                ' If 500ms has not passed since the 'first' scroll event
                Else                          

                    ' Loads header and footer  
                    BindPartNumMovePrevious()           

                    ' sets number of scrolls to anything but 0
                    numberOfScrolls = 1                                 
                End If
            End If

        ' These cases can be ignored for now
        Case 3, 4                                                       
            If iDelta < 0 Then
                BindRefDesMoveNext()
            Else
                BindRefDesMovePrevious()
            End If
    End Select

End Sub

在我尝试的这个版本中,问题是如果 500ms 没有在特定的鼠标滚轮滚动上传递,则 dgv 永远不会加载(即,如果最后一个 wheelScroll 事件发生在 mouseScrollStopWatch.ElapsedMilliseconds

关于如何从鼠标滚轮捕获更多数据有什么建议吗?最终目标只是提高我浏览记录的速度,因此我愿意接受其他不围绕我在此处概述的解决方案的解决方案。

我试图具体一点,但我可能会接近它以意识到我没有包含重要信息。如果我不是,请告诉我,我会将其包括在内。

【问题讨论】:

  • 与你的问题不太相关,但通常 cmets 写在代码上方,而不是在旁边。这样读起来要容易得多。
  • 注意到@Eminem。我通常这样做,但 Visual Studios 以我不喜欢的方式格式化 cmets。例如,如果我试图将 cmets 放在“Else”语句之上,Visual Studios 会将注释与前面的“If”语句的代码对齐,这将使其偏移。 Visual Studios 不允许我格式化我的 cmets,但我现在意识到我可以在这里编辑它。
  • 你是对的。我也觉得很烦。但你真的应该阅读this blog about comments。我不是要挑剔或自大,但是像Reset number of Scrolls 这样的cmets 真的没有必要。
  • 我试图通过彻底避免不必要的来回。这显然是惨败。再一次,这不是我通常编写代码的方式。我的编码风格实际上处于评论不足的另一端
  • 如果您在处理 DGV 中的大量数据时遇到问题,您可能对使用虚拟模式感兴趣:Walkthrough: Implementing Virtual Mode in the Windows Forms DataGridView Control

标签: vb.net winforms scroll vb.net-2010 mousewheel


【解决方案1】:

我认为您需要做的就是使用 Timer 来确保在滚动停止 500 毫秒时调用 updateDGV()。我只是使用一个文本框作为滚动的主题,并使用另一个文本框来指示正在发生的事情:

Public Class Form1

    Dim scrollTimer As Timer
    Const SCROLLWAIT As Integer = 500

    Dim iButton As Integer = 1

    Private Sub SetupScrollTimer()
        scrollTimer = New Timer
        scrollTimer.Interval = SCROLLWAIT
        AddHandler scrollTimer.Tick, AddressOf FinalScroll
    End Sub

    Private Sub FinalScroll(sender As Object, e As EventArgs)
        TextBox1.AppendText("updateDGV()" & vbCrLf)
        scrollTimer.Stop()
    End Sub

    Private Sub TextBox2_MouseWheel(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox2.MouseWheel
        scrollTimer.Start()
        Dim iDelta As Integer = e.Delta

        If iDelta < 0 Then
            TextBox1.AppendText("BindPartNumMoveNext()" & vbCrLf)
        Else
            TextBox1.AppendText("BindPartNumMovePrevious()" & vbCrLf)
        End If

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SetupScrollTimer()

    End Sub

End Class

Windows.Forms.Timer.Start() 旨在将计时器重置为零,但仍然存在对 updateDGV() 的虚假调用。如果这些是问题,那么您将需要调整代码(问题留给读者练习)。

【讨论】:

  • 谢谢@Andrew!!这正是我一直在寻找的。非常感谢!
  • @ChrisSearcy 不客气 :) 我有点怀疑你最好使用 System.Timers.Timer 来避免我发现的虚假调用,尽管它可能不是您的 UI 的问题 - 用户偶尔看到额外的更新可能会更好。但是,使用计时器而不是秒表的原则仍然存在。