问题的名称是:“从后台工作者更新GUI”,但正确的名称世界是:“从后台工作者更新GUI或从后台工作者报告多个变量(除了整数)”
请让我解释一下我的情况.在一个程序中,我有一个后台工作者来分析信息.作为这种分析的结果 – 形式GUI元素应该填充必要的数据.在GUI中我想更新
> 2 datagridviews
> 1个列表框
> 5个标签
据我所知 – 我只能通过后台工作者的ReportProgress()方法本地报告1个int值.
所以问题是 – 如何传递List<> (一些其他变量:string,int)通过ReportProgress()?基本上 – 我想用信息更新GUI,但“1整数”不会这样做.所以要么可以通过ReportProgress()传递多个变量,或者我可以使用BackgroundWorker内部的Invoke来更新GUI ..我个人不喜欢Invoke方法…你有什么看法?
private void button9_Click(object sender,EventArgs e) // start BW { bw.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); bw.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; bw.RunWorkerAsync(10); } private void button10_Click(object sender,EventArgs e) // cancel BW { bw.CancelAsync(); } private void backgroundWorker1_DoWork(object sender,DoWorkEventArgs e) { int count = (int)e.Argument; for (int i = 1; i <= count; i++) { if (bw.CancellationPending) { e.Cancel = true; break; } List<List<string>> list_result = new List<List<string>>(); list_result = Proccess(); bw.ReportProgress(list_result.Count()); // right now I can only return a single INT /////////// UPDATE GUI ////////////// // change datagridview 1 based on "list_result" values // change datagridview 2 // change listBox // change label 1 // change label .. Thread.Sleep(20000); } MessageBox.Show("Complete!"); e.Result = sum; } private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e) { prog_count++; listBox1.Items.Add("Count: (" + prog_count.ToString() + "/20). Found: " + e.ProgressPercentage.ToString() + "."); }
解决方法
调用ReportProgress时有一个UserState参数.
var list_result = new List<List<string>>(); new backgroundWorker1.ReportProgress(0,list_result);
参数类型是一个对象,因此您必须将其强制转换为您需要的类型:
void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e) { var userState = (List<List<string>>)e.UserState; }
这个棘手的问题是,如何确定您是否传回List,列表或单个字符串,数字等.您必须在ProgressChanged事件中测试每种可能性.
void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e) { var myList = e.UserState as List<List<string>>; if (myList != null) { // use list return; } int myNumber; if (Int32.TryParse(e.UserState.ToString(),out myNumber)) { // use number return; } var myString = e.UserState.ToString(); // use string }
或者,您可以创建一个包含所需所有值的类(或使用Tuple
),在后台运行所有内容以填充该类,然后将其传递给RunWorkerCompleted事件,并从那里一次更新UI.