我怎样才能放弃BGW而使用异步/等待任务,我愿意在使用VS2013的时候学习这项技术。
我在网上查看了示例,但我仍然无法自己完成,因为我遇到的示例使用了.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;
}
}
}
发布于 2014-12-11 22:00:58
我有一个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();
}
}
}
发布于 2014-12-11 21:25:50
您应该将该方法标记为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;
}
}
https://stackoverflow.com/questions/27423756
复制相似问题