2014-07-03 128 views
1

我的表單應用程序中有服務調用。當我的按鈕被點擊時,我打電話給我的服務方法。這是我的代碼塊:BackgroundWorker with ProgressBar - 跨線程操作無效

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(Style = Marquee)可見。但是由於Cross Thread問題,我無法在完成的方法中將其隱藏起來。

當我試圖在UI線程做一些與BGWorker的完成情況,

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     progressBar1.Visible = false; 
    } 

我得到一個例外:控制「Form1的」訪問:無效

跨線程操作從一個線程而不是它創建的線程。

我該如何處理這個問題?

+0

如果您正確使用它,那是不可能的。 RunWorkerCompleted事件在UI線程上執行,所以你不應該看到這個異常。你是否正在拋出異常的代碼行?仔細檢查堆棧跟蹤。 –

+0

「DoWork」事件更可能發生。 ObservableCollection是否以任何方式綁定到UI?修改'DoWork'事件中的那些_might_可能導致異常......不確定。 –

+0

您的變量'dt'似乎是全局變量,容易受到跨線程問題的影響。 – Srikanth

回答

4

您需要使用invoke()方法用於調用

private delegate void ToDoDelegate(); 
    void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     Invoke(new ToDoDelegate(() => progressBar1.Visible = false)); 
    } 

更多信息() http://msdn.microsoft.com/de-de/library/System.Windows.Forms.Control.Invoke(v=vs.110).aspx

+0

不需要再次調用()其已在UI上運行。檢查[鏈接](http://stackoverflow.com/questions/2806814/backgroundworker-runworkercompleted-事件) – Srikanth

+0

感謝您的答覆,這是有幫助的。通過此操作(Invoke())我創建一個新的線程來做我的外部服務呼叫的作品? – mekafe

0

修改進度的可見性在UI線程上。

Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action) 
        delegate() 
        { 
         progressBar1.Visible = false; 
        }); 
+0

解釋一下,代碼應該做什麼! –

-1

我認爲在RunWorkerCompleted事件中不會引發異常(如在註釋中所述)。我的建議是,您嘗試訪問DoWork事件中的UI組件的行觸發了它。

嘗試將您需要的數據放入DoWork事件到DoWorkEventArgs e。大量的例子如何做到這一點,就像this discussion一樣提供。

當工作完成後,提供「主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()中的代碼肯定不是異常的來源。它內置一個小而簡單的例子來說明我的argment:

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和一個Button來啓動一個BackGroundWorker

工人得到來自TextBox(UI線程)DoWork增加它由1數量並保存爲結果(新線)。此外,它報告增加的號碼爲ProgressBar(跨線程)

最後RunWorkerCompleted讀出結果並將新值存儲在TextBox(UI線程)中。

所以,請重新檢查你的代碼;-)

+0

我將我的服務結果返回給e.Result,但我在progressBar.Visibility = false中得到了同樣的錯誤;在BGWorker的Completed事件? – mekafe

1

這裏是小有一點的代碼塊,我總是愛用,我不記得我是從我把它放在我的Dropbox的一個很久以前。

​​

使用

this.InvokeEx(x => Progressbar1.Visible = false); //Note 'x' could be any variable 

這樣你就不必每次都輸入了這一切,和它是如此簡單易用。只需將該權限添加到表單類的最後(在最後一個括號關閉後)。您可以使用它來安全地執行任何交叉線程操作。

+0

感謝您的關注。本課非常有用。最好的問候。 – mekafe