【问题标题】:Background Worker implementation后台工作者实现
【发布时间】:2016-11-08 15:42:02
【问题描述】:

这是我的后台工作DoWor功能,考虑到GUI操作的实现是否做好了?

       private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
         try
        {

            string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
            SqlConnection con = new SqlConnection(connectionString);
            con.Open();
            string query = "SELECT * FROM dbo.Liguanea_Lane2";
            SqlCommand cmd = new SqlCommand(query, con);

            SqlDataReader dr = cmd.ExecuteReader();
            while (dr.Read())
            {
                string scode = dr.GetString(dr.GetOrdinal("code"));

                comboBox2.Invoke((MethodInvoker)delegate
                {
                    comboBox2.Items.Add(scode);
                });
                }
        }
        catch (Exception ex)
        {

            MessageBox.Show(ex.ToString());
        }
    }

这是调用它的函数:

  private void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
    {
      if(comboBox4.SelectedIndex == 0)
        {
            backgroundWorker1.RunWorkerAsync();

        }
        else
        {

            MessageBox.Show("This table doesn't exist within the database");
        }
    }

目前没有任何反应..代码只是在屏幕上以默认形式运行。没有加载值,我做错了什么?

【问题讨论】:

  • 我想您可以通过直接使用按钮调用backgroundWorker1.RunWorkerAsync(); 来使您的代码正常工作。但是您的后台工作人员在某种程度上是无用的,因为您在 DoWork 事件中执行繁重的 UI 任务。
  • 但我认为使用方法 Invoker 会有所帮助
  • 不,这无济于事。当您使用Invoke 时,您传递给它的操作将在 UI 线程中运行。
  • 我只需要了解如何在这些后台工作函数中正确拆分我的代码。这是我现在代码中唯一的问题,因为当大量操作发生时 UI 会冻结。我只是在看你在我上一篇文章中的解释,我不完全明白。
  • BGW 已过时。它所做的任何事情都可以使用async/await 轻松完成。如果您想在后台查询数据库,则必须使用ExecuteReaderAsync。您所要做的就是将您的事件处理程序定义为async void,然后编写var reader=await cmd.ExecuteReaderAsync();

标签: c# winforms backgroundworker


【解决方案1】:

BGW 已过时。 TPL,async/awaitIProgress<T> 可以解决使用 BGW 的所有情况等等。

在这种情况下,BGW 无论如何都不合适。真正的延迟是由数据库调用引起的,而不是加载 UI。要异步执行数据库调用,您只需使用异步事件处理程序:

private async void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
{
        var conString=Properties.Settings.Default.MyConnectionString;
        string query = "SELECT * FROM dbo.Liguanea_Lane2";                    

        using(var con = new SqlConnection(conString))
        using(var cmd = new SqlCommand(query, con))
        {
            await con.OpenAsync();
            var reader=await cmd.ExecuteReader();
            while (dr.Read())
            {
                string scode = dr.GetString(dr.GetOrdinal("code"));
                comboBox2.Items.Add(scode);
            }
        }
}

虽然有更好的方法来加载组合。一项改进是加载列表中的所有项目,然后使用 AddRange 更新组合。 AddRange 已经调用 BeginUpdate 来阻止 UI 更新,同时从列表中添加项目。

        var items=new List<string>();
        using(var con = new SqlConnection(conString))
        using(var cmd = new SqlCommand(query, con))
        {
            await con.OpenAsync();
            var reader=await cmd.ExecuteReader();
            while (dr.Read())
            {
                string scode = dr.GetString(dr.GetOrdinal("code"));
                list.Add(scode);
            }
        }

        comboBox2.Items.AddRange(items);

更好的是,使用像 Dapper 这样的微 ORM 来摆脱所有这些代码:

using(var con = new SqlConnection(conString))
{
    await con.OpenAsync();
    var items=await con.QueryAsync<string>(query);
    comboBox2.Items.AddRange(items);
}

【讨论】:

  • 有没有办法包含一个进度条来跟踪加载过程?我不确定它是否会快速加载 20k 条记录,或者只是给用户一个加载屏幕来查看
  • @Jevon 当然,使用 async/await 只需在循环中放置一个栏并根据需要进行更新。您仍然在 UI 线程上,因此您可以这样做,就像您将项目添加到组合框中一样。制作条形图最困难的部分是有效地计算要处理的项目总数。
  • 20K 记录的组合是人类无法使用的。在这种情况下,您必须实现可搜索的组合。在任何情况下,您可以更新您想要的任何 UI 控件,因为在 await 控件返回 UI 线程之后
  • @PanagiotisKanavos 从数据库读取 20k 是必要的。这是一个数据输入过程。
  • 人类无法真正从 20K 条记录中挑选。要么您已经使用了自动完成功能,要么您必须找到解决此问题的方法。例如,组合框允许数据绑定到数据源。您可以加载列表中的所有代码,将控件绑定到它并让它根据需要自行更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 2011-03-17
  • 1970-01-01
相关资源
最近更新 更多