程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Visual C#編程技巧兩則(1)

Visual C#編程技巧兩則(1)

編輯:關於C語言

問題:在多線程中調用Winform

我的WinForm程序中有一個用於更新主窗口的工作線程(worker thread),但文檔中卻提示我不能在多線程中調用這個form(為什麼?),而事實上我在調用時程序常常會崩掉。請問如何從多線程中調用form中的方法呢?

解答:

每一個從Control類中派生出來的WinForm類(包括Control類)都是依靠底層Windows消息和一個消息泵循環(message pump loop)來執行的。消息循環都必須有一個相對應的線程,因為發送到一個window的消息實際上只會被發送到創建該window的線程中去。其結果是,即使提供了同步(synchronization),你也無法從多線程中調用這些處理消息的方法。大多數plumbing是掩藏起來的,因為WinForm是用代理(delegate)將消息綁定到事件處理方法中的。WinForm將Windows消息轉換為一個基於代理的事件,但你還是必須注意,由於最初消息循環的緣故,只有創建該form的線程才能調用其事件處理方法。如果你在你自己的線程中調用這些方法,則它們會在該線程中處理事件,而不是在指定的線程中進行處理。你可以從任何線程中調用任何不屬於消息處理的方法。

Control類(及其派生類)實現了一個定義在System.ComponentModel命名空間下的接口 -- ISynchronizeInvoke,並以此來處理多線程中調用消息處理方法的問題:

public interface ISynchronizeInvoke
{
object Invoke(Delegate
method,object[] args);
IAsyncResult BeginInvoke(Delegate
method,object[] args);
object EndInvoke(IAsyncResult
result);
bool InvokeRequired {get;}
}

ISynchronizeInvoke提供了一個普通的標准機制用於在其他線程的對象中進行方法調用。例如,如果一個對象實現了ISynchronizeInvoke,那麼在線程T1上的客戶端可以在該對象中調用ISynchronizeInvoke的Invoke()方法。Invoke()方法的實現會阻塞(block)該線程的調用,它將調用打包發送(marshal)到 T2,並在T2中執行調用,再將返回值發送會T1,然後返回到T1的客戶端。Invoke()方法以一個代理來定位該方法在T2中的調用,並以一個普通的對象數組做為其參數。

調用者還可以檢查InvokeRequired屬性,因為你既可以在同一線程中調用ISynchronizeInvoke也可以將它重新定位(redirect)到其他線程中去。如果InvokeRequired的返回值是false的話,則調用者可以直接調用該對象的方法。

比如,假設你想要從另一個線程中調用某個form中的Close方法,那麼你可以使用預先定義好的的MethodInvoker代理,並調用Invoke方法:

Form form;
/* obtain a reference to the form,
then: */
ISynchronizeInvoke synchronizer;
synchronizer = form;
if(synchronizer.InvokeRequired)
{
MethodInvoker invoker = new
MethodInvoker(form.Close);
synchronizer.Invoke(invoker,null);
}
else
form.Close();

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved