【问题标题】:C# Update DataGridView from BackgroundWorkerC# 从 BackgroundWorker 更新 DataGridView
【发布时间】:2018-10-25 14:51:50
【问题描述】:

仍在努力将实时数据从我的数据库获取到 datagridview。这次我试图通过后台工作人员来做到这一点。它从 doWork 方法提供的唯一东西是 backgroundWorker1_ProgressChanged 方法的 INT。我也想将我的对象(如 DataTable)发送给它,这样我就可以刷新主线程 Form1 上的数据。如何将我的对象传递给 backgroundWorker1_ProgressChanged 事件?在代码中标记了我需要来自 DoWork 的数据的位置

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        string IP_db_mysql = "1";
        string Port_db__mysql = "1";
        string UserName_db__mysql = "1";
        string Password_db__mysql = "1";
        string dbName__mysql = "1";

        string connString = "Server =" + IP_db_mysql + "; Port =" + Port_db__mysql + "; Database =" + dbName__mysql + "; Uid =" + UserName_db__mysql + ";Pwd =" + Password_db__mysql + ";";
        MySqlConnection conn = new MySqlConnection();
        DataTable dt = new DataTable();

        string query = "SELECT * FROM mysql.test_table;";

        int sum = 0;

        for (int i = 1; i <= 10; i++)
        {
            sum = sum + i;

            try
            {
                // open connectipon
                conn.ConnectionString = connString;
                conn.Open();

                // build command
                MySqlCommand cmd = new MySqlCommand(query, conn);

                // execute command
                MySqlDataReader dataReader = cmd.ExecuteReader();

                // fill datatable
                dt.Load(dataReader);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                conn.Close();
            }

            // Calling ReportProgress() method raises ProgressChanged event
            // To this method pass the percentage of processing that is complete
            backgroundWorker1.ReportProgress(i);

            Thread.Sleep(100);

            // Check if the cancellation is requested
            if (backgroundWorker1.CancellationPending)
            {
                // Set Cancel property of DoWorkEventArgs object to true
                e.Cancel = true;
                // Reset progress percentage to ZERO and return
                backgroundWorker1.ReportProgress(0);
                return;
            }
        }

        // Store the result in Result property of DoWorkEventArgs object
        e.Result = sum;
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        labelProgress.Text = e.ProgressPercentage.ToString() + "%";
     **----------->>   dataGridView1.DataSource = HOW TO GET DATATABLE FROM DO WORK METHOD !?  <<------------------------**
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            labelProgress.Text = "Processing cancelled";
        }
        else if (e.Error != null)
        {
            labelProgress.Text = e.Error.Message;
        }
        else
        {
            labelProgress.Text = e.Result.ToString();
        }
    }

    private void button23_Click(object sender, EventArgs e)
    {
        // Check if the backgroundWorker is already busy running the asynchronous operation
        if (!backgroundWorker1.IsBusy)
        {
            // This method will start the execution asynchronously in the background
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void button24_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy)
        {
            // Cancel the asynchronous operation if still in progress
            backgroundWorker1.CancelAsync();
        }
    }

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    在 BackgroundWorker 的 DoWork 末尾,您需要将其 DataSource 设置为您的结果。但是,由于您是在后台工作人员中,如果您直接执行此操作,则会收到异常,因为 WinForms 不允许您从另一个线程访问 UI。

    您可以使用以下代码执行此操作:

    // create a method to handle updating the datasource
    public void UpdateDataGridViewSource(object data)
    {
        // check if we need to swap thread context
        if(this.dataGridView1.InvokeRequired)
        {
            // we aren't on the UI thread. Ask the UI thread to do stuff.
            this.dataGridView1.Invoke(new Action(() => UpdateDataGridViewSource(data)));
        }
        else
        {
            // we are on the UI thread. We are free to touch things.
            this.dataGridView1.DataSource = data;
            this.dataGridView1.DataBind();
        }
    }
    
    // at the end of your DoWork()
    this.UpdateDataGridViewSource(result);
    

    【讨论】:

    • 更新(数据)为红色
    • 抱歉,我在输入时重命名了方法,漏掉了一个位置。
    • 非常感谢,它成功了。但是我的应用程序每次通过数据库连接循环并返回数据时仍然滞后:(移动窗口时每 0.1 秒就会滞后...没有选项...
    • 不幸的是,DataGridViews 不是很快。你一次加载多少条记录?
    • 另外,您应该从后台工作人员中删除Thread.Sleep(),这应该没有必要。
    【解决方案2】:

    使用如下代码所示的状态对象

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.Data.SqlClient;
    using System.Data;
    
    namespace ConsoleApplication76
    {
        class Program
        {
            static void Main(string[] args)
            {
            }
        }
        public enum ReportTypes
        {
            PROGRESS,
            DATATABLE
        }
        public class Report
        {
            public int progress { get; set; }
            public ReportTypes type { get; set; }
            public DataTable table { get; set; }
        }
        public class Worker
        {
            public BackgroundWorker backgroundWorker1 { get; set; }
    
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                Report report = new Report();
                report.progress = 50;
                report.type = ReportTypes.PROGRESS;
                backgroundWorker1.ReportProgress(50, report);
    
                DataTable dt = new DataTable();
                report.table = dt;
                report.type = ReportTypes.DATATABLE;
                backgroundWorker1.ReportProgress(50, report);
            }
    
    
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
               int progress = e.ProgressPercentage;
               Report report =  e.UserState as Report;
    
               switch (report.type)
               {
                   case ReportTypes.PROGRESS :
                      BeginInvoke((MethodInvoker)delegate
                      {
                        WriteStatusAndError("Query Completed");
                      });
                       break;
                   case ReportTypes.DATATABLE :
                       break;
               }
           }
    
    
        }
    }
    

    【讨论】:

    • 请编辑您的代码,您有 2 个“ProgressChanged”事件处理程序,一个应该是“DoWork”。
    • 哪里出错了。现在我被阻止访问您的网页。如果没有更多信息,直到今天晚些时候才能回答。通常你会得到一个跨线程错误,需要使用 BeginInvoke。我在代码的报告进度部分更新了代码。
    • 问题出在:public BackgroundWorker backgroundWorker1 { get;放;我不得不将其更改为: public BackgroundWorker backgroundWorker1 = new BackgroundWorker();进一步测试代码,如果成功,将在此处发布最终解决方案。
    • 后台工作者可以像任何表单控件一样添加,也可以在代码中添加。我假设你使用了表格。我刚刚添加到我的示例代码中,我只是添加它以消除编译器错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    • 2020-09-23
    • 2019-11-02
    • 1970-01-01
    相关资源
    最近更新 更多