【问题标题】:Fill gridview(refresh) while long running process长时间运行过程中填充gridview(刷新)
【发布时间】:2013-02-08 09:36:11
【问题描述】:

我有一个运行不同值的方法,该方法进入数据库,检索值并逐行填充gridview

每次调用都需要一些时间,并且屏幕会冻结,直到进程完成。我喜欢在方法运行且不冻结屏幕的情况下在gridview 中显示值。

我尝试了类似下面的方法,它仍然会冻结屏幕,并且在处理完成之前我看不到网格上的值。

如果我在循环中使用它,我不想使用 Application.Doevents 在网格中显示数据。

感谢您的帮助

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

        Dim t = New Threading.Thread(AddressOf MyWork)
        t.Start()
End Sub


Private Sub MyWork()
        If Me.InvokeRequired Then
            Me.Invoke(New MethodInvoker(AddressOf DoWork))
        End If
End Sub

Private Function DoWork() As Boolean

    For i As Integer = 1 To 1000000
        FillGrid(i)
    Next    
End Function

【问题讨论】:

    标签: .net vb.net winforms multithreading .net-4.0


    【解决方案1】:

    您可以尝试使用具有ProgressChanged 事件的BackgroundWorker 类,该事件允许您在长时间操作期间为用户界面提供中间更新。在DoWork函数中,您可以多次调用ReportProgress并将任意对象传递给ProgressChanged事件以更新UI。

    这里有一个简单的例子来展示这个概念。首先将BackgroundWorkerToolBox 添加到设计器视图中的表单。该实例将显示在设计器窗口的底部。选择BackgroundWorker 并将WorkerReportsProgress 属性设置为等于True

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        BackgroundWorker1.RunWorkerAsync()
    End Sub
    
    Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim list1 As New List(Of String)
        list1.Add("A")
        list1.Add("B")
        list1.Add("C")
        BackgroundWorker1.ReportProgress("50", list1)
        Dim list2 As New List(Of String)
        list2.Add("1")
        list2.Add("2")
        list2.Add("3")
        BackgroundWorker1.ReportProgress("100", list2)
    End Sub
    
    Private Sub BackgroundWorker1_ProgressChanged(sender As System.Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Dim myList As List(Of String)
        myList = e.UserState
        For Each str As String In myList
            DataGridView1.Rows.Add(str)
        Next
    End Sub
    
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        MessageBox.Show("Operation Complete")
    End Sub
    

    这是对正在发生的事情的解释。在DoWork 例程中,您将在separate thread 上执行比UI 更长的操作。当你调用ReportProgress函数时,你可以给它传递两个参数:一个百分比和一个对象……在这种情况下第二个参数更重要。在ProgressChanged 例程中,您将从e.UserState 获取相同的对象,并使用它做您想做的事情。这发生在UI thread 上,因此您可以从这里更新您的控件。 RunWorkerCompleted 例程在操作完成时被调用,并且还在UI thread 上运行。重要的是,每当您调用 ReportProgress 函数时,都会在 BackgroundWorkerUI 之间执行线程安全切换。

    【讨论】:

    • 我尝试了导致cross thread 错误的方法。您知道如何将上述情况转换为后台工作人员吗?
    • @huMptyduMpty 你能告诉我们你做了什么来得到这个错误吗?您可能在错误的方法(线程)中调用了 UI 线程。
    • @Mash:感谢 mash,它运行良好。它确实在进程运行时刷新了网格。但我唯一的问题是表格仍然被冻结,直到过程完成。你知道为什么吗?
    • @huMptyduMpty:可能是因为您有太多行,以至于即使是向您的DataGridView 添加行的行为也会使表单无响应。如果是这种情况,您可能希望先在内存中填充自己的表,然后将DataGridViewDataSource 设置为内存中的表。看看这个example 看看这是不是你可能有兴趣做的事情。
    猜你喜欢
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    • 2020-07-14
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多