我过去在Windows Form应用程序中使用过 BackgroundWorker .对于我的新练习,我需要在worker内部使用 async 方法,对此我有些困惑.
I have used in the past the BackgroundWorker in a Windows Form application. For my new exercise I need to use async methods inside the worker and I am getting a little bit confused about that.
这是我的代码结构.在表单加载事件中,我正在创建 BackgroundWorker 对象和设置事件
This is my code structure. In the form load event I am creating the BackgroundWorker object and setup events
private void fMain_Load( object sender, EventArgs e ) { bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.DoWork += new DoWorkEventHandler( bw_DoWork ); bw.ProgressChanged += new ProgressChangedEventHandler( bw_ProgressChanged ); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler( bw_RunWorkerCompleted ); }当用户单击按钮时,我正在启动工作人员
When the user click a button I am starting the worker
private void btnGenerate_Click( object sender, EventArgs e ) { Settings settings = new Settings(); pbCounter.Visible = true; btnGenerate.Enabled = false; bw.RunWorkerAsync( settings ); }这是工作人员代码
private async void bw_DoWork( object sender, DoWorkEventArgs e ) { try { for ( int ix = 1; i <= 100; i++ ) { using (var client = new HttpClient()) { [???? how to call and wait here ????] HttpResponseMessage response = await client.PostAsync( "endpoint", new StringContent( JsonConvert.SerializeObject( formContent ), Encoding.UTF8, "application/json" ) ); } //The counter will keep track of your process Application.DoEvents(); int percentage = ix * 100 / settings.TotalRuns; bw.ReportProgress( percentage ); } } catch ( Exception ex ) { MessageBox.Show( ex.Message, "Gift Creator", MessageBoxButtons.OK, MessageBoxIcon.Error ); } } 推荐答案如果使用 async 和 await ,则不需要后台工作程序.实际上,您的后台工作者将无法工作,因为当您使用 await 时,控制权将交还给调用者.并且,当 DoWork 处理程序将控制权返回给其调用者时,后台工作程序将终止并且不继续其剩余任务.
If you use async and await there is no need for a background worker. In fact, your background worker would not work because the control is given back to the caller when you use await. And when the DoWork handler returns control to its caller, the background worker will terminate and not continue its remainnig tasks.
因此,我将使按钮处理程序 async 并在那里执行http请求:
So I would make the button handler async and do the http requests there:
private async void btnGenerate_Click(object sender, EventArgs e) { const int totalRuns = 5; pbCounter.Visible = true; pbCounter.Minimum = 0; pbCounter.Maximum = totalRuns; pbCounter.Value = 0; btnGenerate.Enabled = false; try { for ( int i = 1; i <= totalRuns; i++ ) { using (var client = new HttpClient()) await client.PostAsync( "endpoint", new StringContent( JsonConvert.SerializeObject( formContent ), Encoding.UTF8, "application/json" ) ); pbCounter.Value = i; } } catch (Exception ex ) { MessageBox.Show( ex.Message, "Gift Creator", MessageBoxButtons.OK, MessageBoxIcon.Error ); } btnGenerate.Enabled = true; }因此,该处理程序在等待http请求时将控制权交还给调用方(说得过于简单:UI).请求完成后,将在 pbCounter.Value = i 行和UI线程上继续执行!这样您就可以安全地更新进度条,因为您不是从另一个线程执行的.
So this handler gives back the control to the caller (to say it over-simplified: the UI) while waiting for the http request. When the request is finished, the execution is continued at the pbCounter.Value = i line - and on the UI thread! So you can safely update the progress bar, because you're not doing it from another thread.
希望这对您有所帮助.请注意,我将 pbCounter.Maximum 设置为要运行的循环数,因此您无需计算百分比.
I hope this helps you. Note that I set the pbCounter.Maximum to the number of loops you're about to run, so you don't need to calculate the percentage.
更多推荐
使用HttpClient异步方法的BackgroundWorker
发布评论