2011-11-04 73 views
0

我有父窗體和子窗體。父表單包含一個dataGridView(帳戶列表),子表單允許用戶註冊一個帳戶。事件,GUI和線程

子窗體在單獨的線程上啓動。

當賬戶被註冊時,它被添加到SQL數據庫中,並且事件在父窗體訂閱的子窗體上觸發。父窗體然後更新dataGridView以從數據庫添加新值。

問題是,當試圖更新父窗體中的dataGridView時,事件被解僱我得到一個交叉線程錯誤。這是正常的行爲嗎?

+0

與ui控件的任何交互操作都必須從創建控件的線程中完成。假設您使用win窗體,則需要使用Control.BeginInvoke/Invoke方法與另一個線程中創建的控件進行交互 – Loman

回答

0

在你的處理器,你將不得不做一些工作,以使處理器背面的UI線程上......「規範」是使用InvokeRequiredBeginInvoke的以下模式:

private void OnChildFormSaysNewItemsHandler(object sender, EventArgs e) 
{ 
    // Bring on the UI thread 
    if (this.InvokeRequired) 
    { 
     Action<object, EventArgs> handler = OnChildFormSaysNewItemsHandler; 
     this.BeginInvoke(handler, sender, e); 
     return; 
    } 

    // Do the normal work... 
} 
+0

在事件處理程序中會有這樣的事情嗎?this.Invoke((MethodInvoker)delegate fillData(); }); –

+0

在進行「正常工作」部分之後,您將回到UI線程,因此您可以調用'FillData()'而不必擔心invoke(它通常會同步調用UI線程中的某些內容) 。 – Reddog

0

是的,這是正常的,觸發事件的線程是子線程表單。在此事件中運行在mainform中的代碼在子窗體線程中運行。所以這很正常。 我鼓勵你不要在不同的線程中啓動窗體,控件。留在主線程中。但是您可以使用BackgroundWorker或其他任何工具在另一個線程中執行內部進程。

0

是的,您不允許從其他線程訪問UI元素,而不是創建它們。您需要將呼叫整理到父窗體所在的線程(如果您使用winforms,則InvokeRequired是您的朋友)

0

此類行爲是預期的 - WinForms應用程序模型不是線程安全設計。 要與來自非UI線程的控件進行交互,請使用Control.Invoke或Control.BeginInvoke()方法。

例子:

void RefreshData() 
{ 
    // Refresh database here 
} 

void MyOtherThreadCallback() 
{ 
    this.BeginInvoke(new Action(RefreshData())) 
} 
0

你父窗體嘗試更新使用解僱事件的線程的網格視圖。這會導致交叉線程錯誤。爲了避免這種情況,您必須使用您創建控件的線程來更新控件。這通常使用代碼:

if(control.InvokeRequired) 
{ 
    control.Invoke(delegateToThisMethod) 
} 

並在delegateToThisMethod您更新網格視圖。

對這一問題的好深入回答this question

0

你不列出您使用的是什麼版本,但檢查出MSDN上的BackgroundWorker Class,它使基本線程很容易。

你會想看看這些事件:

OnDoWork    Raises the DoWork event. 
OnProgressChanged  Raises the ProgressChanged event. 
OnRunWorkerCompleted Raises the RunWorkerCompleted event. 

在DoWork的方法會發生什麼是一個單獨的線程(以及任何調用),但二者所創建的運行ProgressChanged和RunWorkerCompleted方法在UI線程上,因此可以更新UI元素。