我如何放弃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;
}
}
}
答案 0 :(得分:1)
我有一个series on my blog,其中显示BackgroundWorker
与Task.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;
}
}