2013-03-23 52 views
0

我有兩個線程看起來像這樣的主題accesing .NET控件問題

pbDB_running = true; // start progress bar 

Thread connectDb = new Thread(new ThreadStart(ConnectToDb)); 
Thread runProgress = new Thread(new ThreadStart(RunpbDB)); 

connectDb.Start(); 
runProgress.Start(); 

connectDb.Join(); //wait untill the connection is done 

pbDB_running = false; //stop the progress bar 

正如你可能會猜到,ConnectToDb是用來做與數據庫的連接,而runpbDB正在一個進度條跑在界面上。進度條(pbDB)是通過在設計視圖上拖放創建的Windows.Forms控件。 的runProgress線程運行RunpbDB()至極看起來是這樣的:

private void RunpbDB() 
{ 
    while (pbDB_running) 
    { 
     if (pbDB.Value == 100) pbDB.Value = 0; 
     else pbDB.Value += 1; 
    } 
    pbDB.Value = 0; 
} 

當兩個線程開始我進去RunpbDB()以下異常:

Cross-thread operation not valid: Control 'pbDB' accessed from a thread other than the thread it was created on. 

我能做些什麼來解決這個情況?

回答

2

你有沒有想過使用BackgroundWorker?這可能會讓你的生活變得更輕鬆。你可以設置兩個,一個用於數據庫調用,另一個用於進度條。只聽後臺工作人員ProgressChangedRunWorkerCompleted事件。在MSDN

+0

BackgroundWorker在這裏不起作用,因爲peter想要在UI線程上顯示進度。 – ZafarYousafi 2013-03-23 14:52:00

+0

@ZafarYousafi BackgroundWorker對於Peter想要實現的功能會很好。是的,在目前的形式中,使用全局的'pbDB_running'將不起作用,但要重新編寫代碼以適應後臺工作,Peter可以實現他想要的。 – 2013-03-23 14:57:19

+0

非常感謝,我會用BackgroundWorker – peter 2013-03-23 15:08:21

1

使用Control.Invoke方法來解決這個問題。整個你的解決方案將成爲

private void RunpbDB() 
{ 
    while (pbDB_running) 
    { 
     Invoke((Action)(()=>{ 
     if (pbDB.Value == 100) pbDB.Value = 0; 
     else pbDB.Value += 1;})); 
    } 
     Invoke((Action)(()=>{pbDB.Value = 0;}); 
} 
+0

在這種情況下什麼,runProgress線程執行只有第一次調用,然後執行RunpbDB函數的其餘部分後,才connectDB完成它的工作。 – peter 2013-03-23 15:03:27

1

只是讓你的生活更輕鬆,並使用BackgroundWorker這個,如果你沒有訪問.NET 4.0。如果您可以使用4.0+,請使用TPL。如果你可以使用4.5,你可以使用新的異步/等待功能。 Stack Overflow有很多例子。 Here是來自Stephen Cleary比較它們的鏈接。

+0

謝謝,我只是使用後臺工作 – peter 2013-03-23 15:05:36

0

當UI線程參與被森林狼隊氣餒2.0(跨線程操作調用之前,這是出於安全原因,有兩種方法可以解決這個問題。簡單的方法是設置靜態屬性

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls 

爲false,然後從你的應用程序在全球禁用此項檢查,但不被任何一個建議這個解決方案,並通過我甚至沒有,因爲它再次打開的安全漏洞。 另一種方式是,在方法首先如果UI檢查控制需求調用,如果是,則使用控件的invoke方法再次調用當前方法,然後返回。代碼可以更好地清楚,我想這麼說

private void RunpbDB() 
    { 
     if (pbDB.InvokeRequired) 
     { 
      pbDB.Invoke(new Action(RunpbDB)); 
      return; 
     } 
     while (pbDB_running) 
     { 
      if (pbDB.Value == 100) pbDB.Value = 0; 
      else pbDB.Value += 1; 
     } 
     pbDB.Value = 0; 
    }