Добавление 150 000 записей в listview без замораживания пользовательского интерфейса

#vb.net #winforms #backgroundworker

#vb.net #winforms #backgroundworker

Вопрос:

У меня есть цикл listview, который добавляет 150 000 элементов в мой listview. В целях тестирования я перенес этот код в фоновый рабочий с делегатами, но он по-прежнему зависает в пользовательском интерфейсе. Я пытаюсь найти решение, чтобы оно могло добавлять эти элементы в фоновом режиме, пока я делаю другие вещи в приложении. Какие решения вы, ребята, рекомендуете?

это то, что я использую

    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 " amp; 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
  

Комментарии:

1. 150 кб — это много для пользовательского интерфейса, даже для не веб-приложения.

Ответ №1:

Попробуйте, это отличный пример того, что вам нужно… У меня также был индикатор выполнения, который показывает прогресс и тому подобное, см. Пример изображения, которое прилагается. Также я не видел ни одного делегата, который вам нужен для выполнения такой операции, у меня есть тот, который потребуется. Причина в том, что вы добавляете элементы в элемент управления в потоке пользовательского интерфейса, для добавления элементов нам нужно знать, требуется ли an Invoke , если это так, мы вызываем, иначе мы добавляем элемент в элемент управления… Также я перевел поток в спящий режим, чтобы он мог сделать перерыв; это также предотвращает блокировку пользовательского интерфейса здесь и там, теперь он реагирует без ЗАВИСАНИЯ.

  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 " amp; 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 amp; " 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
  

Скриншот в действии…

введите описание изображения здесь

Комментарии:

1. Могут ли быть проблемы с памятью?

2. Я запускал Ants profiler и не видел ничего подобного. Почему это должно быть?

3. @SysDragon отличный момент. Это может быть возможно, так как это довольно много элементов для ListView. Я не уверен насчет компьютера операционной системы, но у меня есть много, которые не были затронуты. Я даже разделил элементы на куски, и это все равно не имело плохого эффекта и было так же быстро, как если бы я его не разделял.

4. Хорошее решение, это отлично подходит для работы с большими списками данных