向数据网格添加新行时速度很慢

时间:2014-03-18 05:31:18

标签: vb.net winforms performance datagridview backgroundworker

以下代码在第一次向数据网格添加新行时非常慢。它是一个多背景工作者应用程序,将添加线程。有人可以帮忙吗?

Imports System.Threading
Imports Wunnell.Threading

Public Class Form1
    Private ReadOnly randomNumberGenerator As New Random
    Private ReadOnly runningRowsByToken As New Dictionary(Of Guid, DataGridViewRow)

    Private Sub startAllButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startAllButton.Click
        If Me.worker.IsBusy() Then
            'Only run one test at a time.
            MessageBox.Show("Cannot start new tasks.  Please wait for all current tasks to complete.", "Start Tasks Failed", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Else
            'A new test cannot be started while this test is running.
            Me.startAllButton.Enabled = False

            'The running test can be cancelled.
            Me.cancelAllButton.Enabled = True

            'Clear all previous data.
            Me.runningTasksGrid.Rows.Clear()
            Me.completedTasksGrid.Rows.Clear()

            'Start the specified number of background tasks.
            For i = 1 To CInt(Me.taskCountSpinner.Value)
                'Generate a random token to identify each task.
                Me.worker.RunWorkerAsync(Guid.NewGuid(), i)
            Next
        End If
    End Sub

    Private Sub cancelAllButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelAllButton.Click
        'If any tasks are running
        If Me.worker.IsBusy() Then
            Me.worker.CancelAsync()
        End If
    End Sub

    Private Sub worker_DoWork(sender As Object, e As DoWorkEventArgs) Handles worker.DoWork
        'Run each task for between 10 and 20 seconds.
        Dim taskTime = TimeSpan.FromSeconds(Me.randomNumberGenerator.Next(10, 21))

        'Get the token that identifies this task.
        Dim token = DirectCast(e.Token, Guid)

        'Display the initial progress.
        Me.worker.ReportProgress(token, 0)

        'Start timing the task.
        Dim taskTimer = Stopwatch.StartNew()

        Console.WriteLine(e.Argument)

        Do
            Console.WriteLine(e.Argument)
            'Simulate some work.
            Thread.Sleep(500)

            'Display the current progress.
            Me.worker.ReportProgress(token, CInt(taskTimer.ElapsedMilliseconds))

            'Check whether this task has been cancelled.
            If Me.worker.IsCancellationPending(token) Then
                If MessageBox.Show(String.Format("Are you sure that you want to cancel task '{0}'?", token), "Confirm Cancellation", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
                    'Cancel this task.
                    e.Cancel = True
                Else
                    'Remove the cancel flag from this task.
                    Me.worker.ReinstateCancelledOperation(token)
                End If
            End If

            'Keep working while there is work to do, unless the task has been cancelled.
        Loop Until e.Cancel OrElse taskTimer.Elapsed > taskTime

        'Report the result of the task.
        e.Result = taskTimer.Elapsed
    End Sub

    Private Sub worker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles worker.ProgressChanged
        'Get the token that identifies this task.
        Dim token = DirectCast(e.Token, Guid)

        Console.WriteLine(e.Token)

        If Me.runningRowsByToken.ContainsKey(token) Then
            'Get the existing row for this task.
            Dim row = Me.runningRowsByToken(token)

            'Update the elapsed time for this task.
            row.Cells(1).Value = TimeSpan.FromMilliseconds(e.ProgressPercentage)
        Else
            'Create a row for this new task.
            Dim row = Me.runningTasksGrid.Rows(Me.runningTasksGrid.Rows.Add(token,
                                                                            TimeSpan.Zero, "Cancel"))

            'Store the row against the token for this task.
            Me.runningRowsByToken.Add(token, row)
        End If
    End Sub

    Private Sub worker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        'Determine whether any tasks are still running.
        Dim isBusy = Me.worker.IsBusy()

        'A new test can only be started when all tasks have completed.
        Me.startAllButton.Enabled = Not isBusy

        'Running tasks can be cancelled.
        Me.cancelAllButton.Enabled = isBusy

        'Get the token that identifies this task.
        Dim token = DirectCast(e.Token, Guid)

        'Get the row for this task.
        Dim runningRow = Me.runningRowsByToken(token)

        'Remove all record of this running task.
        Me.runningRowsByToken.Remove(token)
        Me.runningTasksGrid.Rows.Remove(runningRow)

        'Add a row for the completed task.
        'Note that the task result is only valid if the task completed normally.
        Me.completedTasksGrid.Rows.Add(e.Token,
                                       If(e.Cancelled, "Cancelled", "Completed"),
                                       If(e.Cancelled, Nothing, e.Result))
    End Sub

    Private Sub runningTasksGrid_CellContentClick(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs)
        'If the user clicked a task's Cancel button...
        If e.ColumnIndex = 2 Then
            '... get the token for that task...
            Dim token = DirectCast(Me.runningTasksGrid.Rows(e.RowIndex).Cells(0).Value, Guid)

            '... and cancel it.
            Me.worker.CancelAsync(token)
        End If
    End Sub
End Class

0 个答案:

没有答案