Generic BackgroundWorker - 填充不同的DataTables / DataGridViews

时间:2013-06-13 16:24:13

标签: .net vb.net datatable backgroundworker

我有一个带有2个按钮的表单,用于填充2个不同的数据网页。

有一个泛型函数,它接受一个SQL语句并执行它。

根据SQL语句的不同,这可能需要一些时间来执行 - 因此我不想锁定UI,而是使用BackgroundWorker,以便在查询运行时显示加载屏幕。

这是没有BGW的初始代码:

Public Class Form1

    Private Sub Query1Button_Click(sender As System.Object, e As System.EventArgs) Handles Query1Button.Click

        Dim sql As String = "SELECT col_1 FROM TABLE_1"
        Dim query1DT As DataTable = getData(sql)

        'now do some other stuff with the datatable
        DataGridView1.DataSource = query2DT
    End Sub

    Private Sub Query2Button_Click(sender As System.Object, e As System.EventArgs) Handles Query2Button.Click

        Dim sql As String = "WHILE 1=1 SELECT col_2 FROM TABLE_2" 'long running query
        Dim query2DT As DataTable = getData(sql)

        'now do some other stuff with the datatable
        DataGridView2.DataSource = query2DT
    End Sub


    Public Shared Function getData(ByVal sql As String) As DataTable

        Dim sqlcon As New SqlClient.SqlConnection
        Dim sqlcomm As New SqlClient.SqlCommand
        Dim sqlda As New SqlClient.SqlDataAdapter
        Dim sqldt As New DataTable

        sqlcon.ConnectionString = "DBConnection"
        sqlcon.Open()
        sqlcomm.Connection = sqlcon
        sqlcomm.CommandText = sql
        sqlda.SelectCommand = sqlcomm
        sqlda.Fill(sqldt)

        Return sqldt

    End Function
End Class

我想将getData函数包装在一个新的BGW线程中,但我不确定如何做到这一点,因为我想填充两个不同的datatables / datagrids。

如果只有1个datagrid,我会怎么做: Imports System.ComponentModel

Public Class Form3

    Private Sub Query1Button_Click(sender As System.Object, e As System.EventArgs) Handles Query1Button.Click

        Dim sql As String = "SELECT col_1 FROM TABLE_1"

        getDataInBackground(sql)

    End Sub

    Private Sub Query2Button_Click(sender As System.Object, e As System.EventArgs) Handles Query2Button.Click
        Dim sql As String = "WHILE 1=1 SELECT col_2 FROM TABLE_2" 'long running query

        Dim query2DT As DataTable = getData(sql)

        'now do some other stuff with the datatable
        DataGridView2.DataSource = query2DT

    End Sub


    Public Sub getDataInBackground(ByVal sql As String)

        'setup worker
        Dim bw As BackgroundWorker = New BackgroundWorker()
        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, New DoWorkEventHandler(AddressOf bw_DoWork)
        AddHandler bw.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf bw_RunWorkerCompleted)
        AddHandler bw.ProgressChanged, New ProgressChangedEventHandler(AddressOf bw_ProgressChanged)

        'Run worker
        bw.RunWorkerAsync(sql)

    End Sub

    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)

        Dim returnDT As DataTable
        returnDT = getData(e.Argument)
        e.Result = returnDT

    End Sub
    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        If e.Cancelled = True Then
            StatusLabel.Text = "Cancelled!"
        ElseIf e.Error IsNot Nothing Then
            StatusLabel.Text = "Error: " & e.Error.Message
        Else

            'now do some other stuff with the datatable
            DataGridView1.DataSource = e.Result

            StatusLabel.Text = "Done!"
        End If
    End Sub

    Private Sub bw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)

        'show loading status
        StatusLabel.Text = "Running"
    End Sub

    Public Shared Function getData(ByVal sql As String) As DataTable

        Dim sqlcon As New SqlClient.SqlConnection
        Dim sqlcomm As New SqlClient.SqlCommand
        Dim sqlda As New SqlClient.SqlDataAdapter
        Dim sqldt As New DataTable

        sqlcon.ConnectionString = "DBConnection"
        sqlcon.Open()
        sqlcomm.Connection = sqlcon
        sqlcomm.CommandText = sql
        sqlda.SelectCommand = sqlcomm
        sqlda.Fill(sqldt)

        Return sqldt

    End Function

End Class

如何使BGW更具通用性,以便我不必在bw_RunWorkerCompleted子内部“现在对数据表执行其他操作”?

1 个答案:

答案 0 :(得分:0)

我认为您可以使用await模式。而不是将你的逻辑放入工作者,因为如果它在完成的事件中,它更像是函数式编程。

await关键字将封装您的后台请求。我不会详细介绍,但有很多教程。它基本上允许您调用操作而不会堵塞UI线程,一旦完成,您的代码将继续在下一行。

http://www.youtube.com/watch?v=ZyFL3hjHADs是我用来学习它的教程。