[英]BackgroundWorker with ProgressBar - Cross-thread operation not valid
我的表格申請中有服務電話。 單擊我的按鈕后,我將調用我的服務方法。 這是我的代碼塊:
void listBox_SelectedValueChanged(object sender, EventArgs e)
{
if (listBox.SelectedItem.Equals("Demo"))
{
progressBar1.Visible = true;
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ObservableCollection<FilterInfo> filterInfos = new ObservableCollection<FilterInfo>();
FilterInfo myFilterObj = new FilterInfo("SUPERVISOR", userName);
filterInfos.Add(myFilterObj);
ObservableCollection<DEMOBec> demos = demoSvc.GetDemoByFilter(filterInfos, false);
dt = new Converter<DEMOBec>().ConvertDataTable(demos.ToList());
}
在調用該服務之前,我使ProgressBar(樣式=選取框)可見。 但是由於跨線程問題,我無法使其在完整的方法中不可見。
當我嘗試在BGWorker的Completed事件中的UI線程中執行某些操作時,
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressBar1.Visible = false;
}
我有一個例外:
跨線程操作無效:控件“ Form1”從創建該線程的線程之外的線程訪問。
我該如何解決這個問題?
您需要使用Invoke()方法
private delegate void ToDoDelegate();
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Invoke(new ToDoDelegate(() => progressBar1.Visible = false));
}
Invoke()的詳細信息http://msdn.microsoft.com/de-de/library/System.Windows.Forms.Control.Invoke(v=vs.110).aspx
這是我一直喜歡使用的小段代碼,我不記得很久以前將其放在Dropbox中的位置。
public static class ControlExtensions
{
public static TResult InvokeEx<TControl, TResult>(this TControl control,
Func<TControl, TResult> func)
where TControl : Control
{
return control.InvokeRequired
? (TResult)control.Invoke(func, control)
: func(control);
}
public static void InvokeEx<TControl>(this TControl control,
Action<TControl> func)
where TControl : Control
{
control.InvokeEx(c => { func(c); return c; });
}
public static void InvokeEx<TControl>(this TControl control, Action action)
where TControl : Control
{
control.InvokeEx(c => action());
}
}
用法
this.InvokeEx( x => Progressbar1.Visible = false); //Note 'x' could be any variable
這樣,您不必每次都鍵入所有內容,並且使用非常簡單。 只需將此權利添加到表單類的末尾(在最后一個括號關閉之后)。 您可以使用它來安全地執行任何跨線程操作。
修改UI線程上ProgressBar的可見性。
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)
delegate()
{
progressBar1.Visible = false;
});
我認為在RunWorkerCompleted
事件中不會引發異常(如評論中所述)。 我的建議是,您嘗試在DoWork
事件中訪問UI cmponent的行會觸發它。
嘗試將DoWork
事件中所需的數據放入DoWorkEventArgs e
。 像這樣的討論在SO上提供了大量示例。
工作完成后,也可以使用事件args向“主UI線程”提供已修改/新的數據,如下所示:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
// do some work
e.Result = ... ; // modified/new data
}
並以以下方式檢索它:
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
var newData = (CastToWhatever) e.Result;
}
希望對您有幫助=)
編輯
您在backgroundWorker1_RunWorkerCompleted()
代碼絕對不是異常的來源。 它構建了一個簡單的示例來說明我的觀點:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync(textBox1.Text);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var num = Int32.Parse(e.Argument.ToString()) + 1;
backgroundWorker1.ReportProgress(num);
e.Result = num;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = (int)e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
textBox1.Text = e.Result.ToString();
}
它能做什么? 在WinForm上,有一個帶有數字的TextBox
,一個ProgressBar
和一個用於啟動BackGroundWorker
的Button
。
worker從TextBox
(UI線程)獲取該數字, DoWork
將其增加1
並將其保存為result (新線程) 。 另外,它將增加的數字報告給ProgressBar
(跨線程) 。
最后, RunWorkerCompleted
讀取結果並將新值存儲在TextBox
(UI線程)中 。
因此,請重新檢查您的代碼;-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.