我使用BackgroundWorker
发送异步HTTP请求(顺便说一下,使用RestSharp),并且需要将返回的数据(HTTP响应)传递给主线程,以根据该数据更新某些GUI组件。为此,我使用ReportProgress
方法,如下所示:
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
Object[] args = (Object[])e.Argument;
string strURL = args[0].ToString();
string strParam = args[1].ToString();
for (int i=0; i<5; i++) {
var client = new RestClient(strURL);
var request = new RestRequest(strURL, Method.POST);
request.AddParameter("someparam", strParam);
client.ExecuteAsync(request, response =>
{
string strRet = response.Content;
worker.ReportProgress(i, strArr);
}
}
}
此代码将引发ReporProgress
上的异常,说当Background Worker
已经完成其工作时调用此方法是非法的,并且它绝对正确,因为当我收到HTTP响应时bw_DoWork
已经完成执行。
因此,您可以看到我正在处理已经异步的后台工作线程中的异步任务。
我知道ReportProgress
被封送在GUI线程上执行,我没有看到任何其他方法将数据传回主表单。如何修复/纠正?
答案 0 :(得分:1)
你需要一些方法让你的后台工作人员睡觉/等待,直到所有的ExecuteAsync都完成。 你可以这样做。
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
Object[] args = (Object[])e.Argument;
string strURL = args[0].ToString();
string strParam = args[1].ToString();
int finishedCounter = 0;
// A reset event that is set from the last ExecuteAsync
AutoResetEvent finishedEvent = new AutoResetEvent(false);
for (int i=0; i<5; i++) {
var client = new RestClient(strURL);
var request = new RestRequest(strURL, Method.POST);
request.AddParameter("someparam", strParam);
client.ExecuteAsync(request, response =>
{
string strRet = response.Content;
worker.ReportProgress(i, strArr);
// Check if this is the last worker/step then
// wake up the background worker to finish the do_work method
if (Interlocked.Increment(ref finishedCounter) == 5)
finishedEvent.Set();
});
}
// wait till work is done
finishedEvent.WaitOne();
}
另一种方法是根本不使用BackgroundWorker。 您可以使用MainWindow的调度程序更新WPF中的UI。
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
// Update UI
});
or
System.Windows.Application.Current.MainWindow.Dispatcher.Invoke(() =>
{
// Update UI
});
或使用具体表单的Windows窗体
System.Windows.Forms.Form form = ...;
form.Invoke(new Action( () =>
{
//Update UI
}));