【问题标题】:Adding 150,000 records to a listview without freezing UI在不冻结 UI 的情况下将 150,000 条记录添加到列表视图
【发布时间】:2014-06-26 02:30:34
【问题描述】:

我有一个列表视图循环,它将 150,000 个项目添加到我的列表视图中。出于测试目的,我将此代码移至具有委托的后台工作人员,但它仍然冻结了 UI。我正在尝试找到一个解决方案,以便它可以在后台添加这些项目,同时我在应用程序中执行其他操作。大家有什么推荐的解决方案?

这就是我正在使用的

   Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ListView1.Clear()

        ListView1.BeginUpdate()

        bw.WorkerReportsProgress = True
        bw.RunWorkerAsync()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        If bw.IsBusy Then bw.CancelAsync()
    End Sub

    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
        For x = 1 To 125000
            Dim lvi As New ListViewItem("Item " & x)
            If bw.CancellationPending Then
                e.Cancel = True
                Exit For
            Else
                bw.ReportProgress(0, lvi)
            End If
        Next
    End Sub

    Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bw.ProgressChanged
        Try
            Dim lvi As ListViewItem = DirectCast(e.UserState, ListViewItem)
            Me.ListView1.Items.Add(lvi)
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try
    End Sub

    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
        ListView1.EndUpdate()
        If Not e.Cancelled Then
            Debug.Print("Done")
        Else
            Debug.Print("Cancelled")
        End If
    End Sub
End Class

【问题讨论】:

  • 150k 可以放入 UI 中,即使对于非 Web 应用程序也是如此。

标签: vb.net winforms backgroundworker


【解决方案1】:

试一试,这是您需要的一个很好的示例...我还有一个显示进度的进度条等,请参阅随附的示例图片。此外,我没有看到您需要执行此类操作的任何代表,我的代表需要一个。原因是您正在向 UI 线程上的控件添加项目,为了添加项目,我们需要知道是否需要 Invoke,如果需要,我们调用否则我们将项目添加到控件......我也做了线程睡眠,所以它可以休息一下;这也防止用户界面想在这里和那里锁定,现在它可以响应 NO FREEZING

 Option Strict On
 Option Explicit On

Public Class Form1

Delegate Sub SetListItem(ByVal lstItem As ListViewItem) 'Your delegate..

'Start the process...
Private Sub btnStartProcess_Click(sender As Object, e As EventArgs) Handles btnStartProcess.Click
    lvItems.Clear()
    bwList.RunWorkerAsync()
End Sub

Private Sub AddListItem(ByVal lstItem As ListViewItem)
    If Me.lvItems.InvokeRequired Then 'Invoke if required...
        Dim d As New SetListItem(AddressOf AddListItem) 'Your delegate...
        Me.Invoke(d, New Object() {lstItem})
    Else 'Otherwise, no invoke required...
        Me.lvItems.Items.Add(lstItem)
    End If
End Sub

Private Sub bwList_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bwList.DoWork
    Dim intCount As Integer = CInt(txtCount.Text)
    Dim dblPercent As Integer = 100
    Dim intComplete As Integer = 0
    Dim li As ListViewItem = Nothing

    For i As Integer = 1 To CInt(txtCount.Text)
        If Not (bwList.CancellationPending) Then
            li = New ListViewItem
            li.Text = "Item " & i.ToString
            AddListItem(li)
            Threading.Thread.Sleep(1) 'Give the thread a very..very short break...
        ElseIf (bwList.CancellationPending) Then
            e.Cancel = True
            Exit For
        End If

        intComplete = CInt(CSng(i) / CSng(intCount) * 100)
        If intComplete < dblPercent Then
            bwList.ReportProgress(intComplete)
        End If

        If li IsNot Nothing Then
            li = Nothing
        End If
    Next

End Sub

Private Sub bwList_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bwList.ProgressChanged
    pbList.Value = e.ProgressPercentage
End Sub

Private Sub bwList_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bwList.RunWorkerCompleted
    If pbList.Value < 100 Then pbList.Value = 100
    MessageBox.Show(lvItems.Items.Count.ToString & " items were added!")
End Sub

Private Sub btnStopWork_Click(sender As Object, e As EventArgs) Handles btnStopWork.Click
    bwList.CancelAsync()
End Sub

Private Sub btnRestart_Click(sender As Object, e As EventArgs) Handles btnRestart.Click
    pbList.Value = 0
    lvItems.Items.Clear()
    txtCount.Text = String.Empty
End Sub
End Class

实际截图...

【讨论】:

  • 会不会有内存问题?
  • 我使用 Ants profiler 运行,但没有看到任何类似的东西。为什么会有?
  • @SysDragon 好点。这可能是可能的,因为对于 ListView 来说这是相当多的项目。我不确定 OP 的电脑,但我的电脑有很多没有受到影响。我什至把物品分成了块,它仍然没有产生不好的效果,就像我没有把它分开一样快。
  • 不错的解决方案,非常适合处理大量数据
猜你喜欢
  • 2012-02-07
  • 2018-04-30
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 2011-12-27
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
相关资源
最近更新 更多