将代码从BGW转换为Async,并将Await转换为DataTabale / MySQLDataAdapter

时间:2014-12-11 13:14:06

标签: c# async-await task backgroundworker

我如何放弃BGW并使用异步/等待任务,我愿意在使用VS 2013时学习这项技术。

我在线查看了这些示例,但我仍然无法自己动手,因为我遇到的示例是使用已经返回任务的.NET中的现有函数。我试图将BGW DoWork中的代码分开并创建一个任务,但编译器一直在问我有关等待的事情,无论如何我都无法调用该任务,我注意到需要时间的行是:

SQLDataAdapter = new MySqlDataAdapter(SQLcmd);
SQLDataAdapter.Fill(dt);

我需要的是:在按钮内单击以启动从数据库中读取的任务,然后释放窗体暂停(假设我没有使用BGW),然后读取结果并在datagridview中显示它们。

// code starts here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using System.IO;

namespace MySQLProject
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            string stdNo = File.ReadAllText("stdNo.txt").Replace(Environment.NewLine, ",");


            const string cs = @"what ever";
            MySqlConnection conn = new MySqlConnection(cs);
            MySqlDataAdapter SQLDataAdapter = new MySqlDataAdapter(); ;
            DataSet ds = new DataSet();
            conn.Open();
            this.InvokeEx(x => x.textBox1.AppendText(string.Format("MySQL version : {0};", conn.ServerVersion)));

            DataTable dt = new DataTable("StudentNamesAndNumbers");
            dt.Columns.Add("Student Name", typeof(string));
            dt.Columns.Add("Student ID", typeof(string));
            dt.Columns.Add("First", typeof(float));
            dt.Columns.Add("Second", typeof(float));
            dt.Columns.Add("Section", typeof(string));
            ds.Tables.Add(dt);

            try
            {

                MySqlCommand SQLcmd = new MySqlCommand();
                SQLcmd = conn.CreateCommand();
                SQLcmd.CommandText = String.Format(@"Select u.firstname as 'Student Name', u.username as 'Student ID'"
                                                    + ",( select  score from gradebook_result g , gradebook_evaluation e "
                                                    + "where g.user_id = u.user_id "
                                                    + "and name = 'First' "
                                                    + "and g.evaluation_id = e.id "
                                                    + "and e.course_code = c.course_code) as 'First' "
                                                    + ",( select  score from gradebook_result g , gradebook_evaluation e "
                                                    + "where g.user_id = u.user_id "
                                                    + "and name = 'Second' "
                                                    + "and g.evaluation_id = e.id "
                                                    + "and e.course_code = c.course_code) as 'Second' "
                                                    + ", c.course_code as 'Section'"
                                                    + "from user u, course_rel_user c "
                                                    + "where "
                                                    + "u.username in ({0}) "
                                                    + "and u.username REGEXP '[0-9]+' "
                                                    + "and c.course_code like 'IT102CPLUS%' "
                                                    + "and  u.user_id = c.user_id ;", stdNo);

                this.InvokeEx(x => x.textBox1.AppendText(SQLcmd.CommandText));

                SQLDataAdapter = new MySqlDataAdapter(SQLcmd);
                SQLDataAdapter.Fill(dt);
                dt.DefaultView.Sort = "Section ASC, Student Name ASC";
                this.InvokeEx(x => x.dataGridView1.Columns.Clear());
                this.InvokeEx(x => x.dataGridView1.DataSource = ds.Tables["StudentNamesAndNumbers"]);
                this.InvokeEx(x => x.dataGridView1.AutoResizeColumns());
                this.InvokeEx(x => x.label1.Text = dt.Rows.Count.ToString() + " Students");

                // =======================================================

                var lines = new List<string>();

                string[] columnNames = dt.Columns.Cast<DataColumn>().
                                                  Select(column => column.ColumnName).
                                                  ToArray();

                var header = string.Join(",", columnNames);
                lines.Add(header);

                var valueLines = dt.AsEnumerable().Select(row => string.Join(",", row.ItemArray));            
                lines.AddRange(valueLines);

                File.WriteAllLines("Export.csv", lines, Encoding.UTF8);

            }
            catch (MySqlException ex)
            {
                this.InvokeEx(x => x.textBox1.AppendText(string.Format("Error: {0}\n\n", ex.ToString())));
            }
            finally
            {
                if (conn != null)
                {
                    conn.Close();
                }
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Enabled = true;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我有一个series on my blog,其中显示BackgroundWorkerTask.Run的对比情况。

通常,您不应该将这些方法中的任何一种用于I / O绑定操作。但是,有一些较旧的API尚未升级以公开TAP方法。我认为“数据适配器”和“数据表”API被认为太旧而无法升级,因此您无法使用“FillAsync”。

所以 - 假设您想要保留“数据表”方法 - 您可以直接使用Task.Run替换BackgroundWorker。请注意IProgress<T>是一种更现代的方式,可以对进度更新进行任何类型的跨线程调用:

private async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    var progress = new Progress<string>(update => textBox1.AppendText(update));
    var ds = await Task.Run(() => BackgroundWork(progress));
    dataGridView1.Columns.Clear();
    dataGridView1.DataSource = ds.Tables["StudentNamesAndNumbers"];
    dataGridView1.AutoResizeColumns();
    label1.Text = dataGridView1.Rows.Count.ToString() + " Students";
    button1.Enabled = true;
}

private DataSet BackgroundWork(IProgress<string> progress)
{
    string stdNo = File.ReadAllText("stdNo.txt").Replace(Environment.NewLine, ",");

    const string cs = @"what ever";
    MySqlConnection conn = new MySqlConnection(cs);
    MySqlDataAdapter SQLDataAdapter = new MySqlDataAdapter(); ;
    DataSet ds = new DataSet();
    conn.Open();
    if (progress != null)
        progress.Report(string.Format("MySQL version : {0};", conn.ServerVersion));

    DataTable dt = new DataTable("StudentNamesAndNumbers");
    dt.Columns.Add("Student Name", typeof(string));
    dt.Columns.Add("Student ID", typeof(string));
    dt.Columns.Add("First", typeof(float));
    dt.Columns.Add("Second", typeof(float));
    dt.Columns.Add("Section", typeof(string));
    ds.Tables.Add(dt);

    try
    {
        MySqlCommand SQLcmd = new MySqlCommand();
        SQLcmd = conn.CreateCommand();
        SQLcmd.CommandText = String.Format(@"Select u.firstname as 'Student Name', u.username as 'Student ID'"
                                                + ",( select  score from gradebook_result g , gradebook_evaluation e "
                                                + "where g.user_id = u.user_id "
                                                + "and name = 'First' "
                                                + "and g.evaluation_id = e.id "
                                                + "and e.course_code = c.course_code) as 'First' "
                                                + ",( select  score from gradebook_result g , gradebook_evaluation e "
                                                + "where g.user_id = u.user_id "
                                                + "and name = 'Second' "
                                                + "and g.evaluation_id = e.id "
                                                + "and e.course_code = c.course_code) as 'Second' "
                                                + ", c.course_code as 'Section'"
                                                + "from user u, course_rel_user c "
                                                + "where "
                                                + "u.username in ({0}) "
                                                + "and u.username REGEXP '[0-9]+' "
                                                + "and c.course_code like 'IT102CPLUS%' "
                                                + "and  u.user_id = c.user_id ;", stdNo);

        if (progress != null)
            progress.Report(SQLcmd.CommandText);

        SQLDataAdapter = new MySqlDataAdapter(SQLcmd);
        SQLDataAdapter.Fill(dt);
        dt.DefaultView.Sort = "Section ASC, Student Name ASC";
        var lines = new List<string>();

        string[] columnNames = dt.Columns.Cast<DataColumn>().
                                              Select(column => column.ColumnName).
                                              ToArray();

        var header = string.Join(",", columnNames);
        lines.Add(header);

        var valueLines = dt.AsEnumerable().Select(row => string.Join(",", row.ItemArray));            
        lines.AddRange(valueLines);

        File.WriteAllLines("Export.csv", lines, Encoding.UTF8);
        return ds;
    }
    catch (MySqlException ex)
    {
        if (progress != null)
            progress.Report(string.Format("Error: {0}\n\n", ex.ToString()));
    }
    finally
    {
        if (conn != null)
        {
            conn.Close();
        }
    }
}

答案 1 :(得分:0)

您应该将方法标记为async并尽可能等待异步方法。 如果没有异步方法并且您想在另一个线程上运行同步方法,请等待Task.Run

    private async void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        try
        {
            //Use an async method when there is one available
            string stdNo;
            using (var reader = File.OpenText("Words.txt"))
            {
                stdNo = await reader.ReadToEndAsync();
            }
            stdNo = stdNo.Replace(Environment.NewLine, ",");

            const string cs = @"what ever";
            MySqlConnection conn = new MySqlConnection(cs);
            MySqlDataAdapter SQLDataAdapter = new MySqlDataAdapter(); ;
            DataSet ds = new DataSet();

            //Use Task.Run to call a long running code on another thread
            //If available you should use await conn.OpenAsync();
            await Task.Run(() => conn.Open());
            //You don't need invoke, after an await you are back to the synchronization context
            textBox1.AppendText(string.Format("MySQL version : {0};", conn.ServerVersion));

            DataTable dt = new DataTable("StudentNamesAndNumbers");
            dt.Columns.Add("Student Name", typeof(string));
            dt.Columns.Add("Student ID", typeof(string));
            dt.Columns.Add("First", typeof(float));
            dt.Columns.Add("Second", typeof(float));
            dt.Columns.Add("Section", typeof(string));
            ds.Tables.Add(dt);
            //...
        }
        finally
        {
            button1.Enabled = true;
        }


    }