【发布时间】:2018-01-31 18:37:12
【问题描述】:
我有许多项目,其中后台线程用于执行长时间运行的工作,并且在从长时间运行的任务更新 UI 之前使用 bool 来标记线程是否已完成(在一些旧的任务中使用的技术NET 3.5 项目)。这是一种不受欢迎的方法,BackgroundWorker 或 Task(首选)更好。
我使用 BackgroundWorker(见下文)创建了一个简单的测试项目,它可以工作,但我找不到使用 Task 执行此操作的完整工作示例,并且每次尝试都会锁定 UI 或引发异常。我的问题是如何使用 Task 执行此操作?
这是代码 - 它只是一个带有一个图表和两个按钮的 Winforms 项目:
public partial class Form1 : Form
{
BackgroundWorker worker = new BackgroundWorker();
DataProvider dataProvider = new DataProvider();
private double[] data;
public Form1()
{
InitializeComponent();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.WorkerReportsProgress = false;
worker.WorkerSupportsCancellation = true;
}
private void button1_Click(object sender, EventArgs e)
{
while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); }
((Button)sender).Enabled = false;
MessageBox.Show("Please wait");
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
data = dataProvider.ReturnPlotData();
}
catch (Exception ex) { MessageBox.Show($"ERROR: {ex.StackTrace.ToString()}"); ; }
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) { MessageBox.Show("BackgroundWorker task cancelled"); }
else if (e.Error != null) { MessageBox.Show($"ERROR during task execution: {e.Error.StackTrace.ToString()}"); }
else
{
try
{
UpdatePlot(data);
}
catch (Exception ex) { MessageBox.Show($"ERROR: {ex.StackTrace.ToString()}"); ; }
}
button1.Enabled = true;
}
private void UpdatePlot(double[] data)
{
chart1.Series.Add("Data");
chart1.Series[0].ChartType = SeriesChartType.Line;
for (int i = 0; i < data.Length; i++) { chart1.Series[0].Points.Add(data[i]); }
}
private void Form1_Load(object sender, EventArgs e) { while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); } }
private void button2_Click(object sender, EventArgs e) { MessageBox.Show("I'm doing something else now..."); }
}
internal class DataProvider
{
public double[] ReturnPlotData()
{
Thread.Sleep(10000);
return new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
}
这是一次转换尝试。这给了我一个类型转换错误(Task vs Task double[]):
public partial class Form1 : Form
{
DataProvider dataProvider = new DataProvider();
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { while (chart1.Series.Count > 0) { chart1.Series.RemoveAt(0); } }
private void button1_Click(object sender, EventArgs e)
{
Task<double[]> task = Task.Run(() =>
{
dataProvider.ReturnPlotData();
}).ContinueWith(t => UpdatePlot(task.Result));
}
private void button2_Click(object sender, EventArgs e) { MessageBox.Show("I'm doing something else now..."); }
private void UpdatePlot(double[] data)
{
chart1.Series.Add("Data");
chart1.Series[0].ChartType = SeriesChartType.Line;
for (int i = 0; i < data.Length; i++) { chart1.Series[0].Points.Add(data[i]); }
}
}
internal class DataProvider
{
public double[] ReturnPlotData()
{
Thread.Sleep(10000);
return new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
}
【问题讨论】:
-
您能否发布一些使其基于任务的努力?这样我们就有了一个工作的起点,即使他们现在失败了。
-
“这给了我一个类型转换错误(Task vs Task double[])”——你从哪里得到这个错误? 确切地说的错误是什么?另外,请注意您应该使用
private async void button1_Click(...),然后不要显式使用ContinueWith(),而是可以使用UpdatePlot(await Task.Run(dataProvider.ReturnPlotData));。 (确实,现在我知道你会在哪里得到那个错误......ContinueWith()方法返回一个Task......你甚至不需要,所以task变量可以完全省略。但是使用async/await反正我说过)
标签: c# winforms task backgroundworker