c#子線程調用主線程控件

相信對多線程有所瞭解的人都知道,子線程是不能直接操作winform上的控件的,因爲默認的控件是在主線程上生成的,子線程是不能直接訪問或者修改的,直接訪問或者修改控件屬性的話會報錯。這個即使在Java上也是這樣,Android中也經常被用到的。

這樣的話,子線程豈不是沒辦法訪問主線程生成的控件了,當然是否定的,有問題就用解決辦法,微軟的人更瞭解這一點,並且有好幾種解決辦法,主要的思路就是在子線程裏,使用delegate代理一個主線程裏面的方法。直接看代碼:

private void showDateTimeMethod()
{
while (true)
{
//顯示當前時間
label1.Text = "當前時間 " + DateTime.Now.ToString();
//線程暫停
Thread.Sleep(1000);
}
}

private void Form1_Load(object sender, EventArgs e)
{
//新建一個線程
Thread showDateTimethread = new Thread(new ThreadStart(showDateTimeMethod));
//該線程爲後臺線程
showDateTimethread.IsBackground = true;
//線程啓動
showDateTimethread.Start();
}

這樣寫的話,毫無疑問會報錯,就是咱們上面說到的情況,子線程直接操作ui元素。我們對這個進行改造一下:

//聲明一個委託類型,該委託類型無輸入參數和輸出參數
public delegate void ProcessDelegate();  
//函數引用,label控件顯示當前時間,輸入參數無,輸出參數無,和聲明的委託類型形式一致
public void LabelShow()
{
   label1.Text = "當前時間 " + DateTime.Now.ToString();
}

然後在線程中實例化一個委託變量,指向這個函數引用。

while (true)
{
//使用命名方法
ProcessDelegate showProcess = new ProcessDelegate(LabelShow);
//調用label的invoke方法
label1.Invoke(showProcess); 
//線程暫停
Thread.Sleep(1000);
}

這樣的話就能執行成功了。在這裏showDateTimethread.IsBackground = true;必須要加上。不知道大家注意沒有,如果子線程裏有 死循環(有時間必須用循環)或子線程在進行一個阻塞式的操作,如影響隊列裏的消息,那麼不能主線程用什麼方式終止子線程都沒門,
  this.thread.Suspend();
  this.thread.Abort()
通通不管用,Abort() 方法也只是建議子線程終止,而不是無條件強行終目,這個不好,比如應用程序要退出,子線程結束不了會一直駐留內存exe都不會退出進程,有什麼辦法強行終止子線程哈,不要說類似於(不要用死循環,無意義之類的話,那對阻塞式的操作怎麼說呢)
這一句的時候把線程阻死了 System.Messaging.Message m = q.Receive(); 
不管等多少,線程都是死的。

可以試試在退出的時候用
System.Environment.Exit(System.Environment.ExitCode);
Application.Exit();
還用在那些線程開始前,使用它的屬性IsBackground,把它設爲true,這樣在你程序結束的時候,線程也會自動結束。

大家都知道隨着linq和ef的流行,一個新的概念出現了,而且目前比較流行,那就是lambda,匿名函數,大家都知道,匿名函數可以用委託進行操作,可以說他是委託初始化的一種新的,便捷的形式,同樣的道理,傳統的委託必須得聲明一個新的方法,才能使用委託,但是匿名函數,可以省去重新聲明一個函數,直接看代碼:

while (true)
{
//實例化一個委託變量,使用匿名方法構造
ProcessDelegate showProcess = delegate()
{
  label1.Text = "當前時間 " + DateTime.Now.ToString();
};
label1.Invoke(showProcess);
//線程暫停
Thread.Sleep(1000);
}

這樣一來的話,簡單明瞭,省去很多代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章