天天看點

WinForm 多線程

<a href="http://www.cnblogs.com/yencain/articles/1375616.html">http://www.cnblogs.com/yencain/articles/1375616.html</a>

環境:VS2008、C#3.0

在WinForm開發中,我們通常不希望當窗體上點了某個按鈕執行某個業務的時候,窗體就被卡死了,直到該業務執行完畢後才緩過來。一個最直接的方法便是使用多線程。多線程程式設計的方式在WinForm開發中必不可少。

本文介紹在WinForm開發中如何使用多線程,以及線上程中如何通過Control.Invoke方法傳回窗體主線程執行相關操作。

-. WinForm多線程程式設計

1. new Thread()

    新開一個線程,執行一個方法,沒有參數傳遞:

private void DoWork() {

            Thread t = new Thread(new ThreadStart(this.DoSomething));

            t.Start();

 }

private void DoSomething() {

            MessageBox.Show("thread start");

新開一個線程,執行一個方法,并傳遞參數:

private void DoWork() {

            Thread t = new Thread(new ParameterizedThreadStart(this.DoSomething));

            t.Start("guozhijian");

}

private void DoSomething(object o) {

            MessageBox.Show(o.ToString());

參數定義為object類型。

2. ThreadPool

    衆所周知,新開一個線程代價是很高昂的,如果我們每個操作都新開一個線程,那麼太浪費了,于是,下面使用線程池。

    無參數傳遞:

            ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomething));

private void DoSomething(object o) {

有參數傳遞:

            ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomething), "guozhijian");

            MessageBox.Show(o.ToString());

使用匿名方法更靈活:

            string name = "guozhijian";

            ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o){

                MessageBox.Show(name);

            }));

在匿名代碼段裡面可以直接通路局部變量,不用在關心參數傳遞的問題

二. Invoke

1. this.Invoke

現在,在業務線程裡面執行完畢,要改變窗體控件的值了,此時,如果直接通過this得到控件的句柄,然後對它進行操作是會抛異常的,.Net WinForm Application裡面是不允許這樣的操作的。這是,可以調用Invoke方法

2.Invoke方法簽名:

object Control.Invoke(Delegate Method)

object Control.Invoke(Delegate Method, params object[] args)

3.使用自定義委托

            WaitCallback wc = new WaitCallback(this.DoSomething);

            ThreadPool.QueueUserWorkItem(wc, "Guozhijian");

WinForm 多線程

private delegate void MyInvokeDelegate(string name);

            this.Invoke(new MyInvokeDelegate(this.ChangeText), o.ToString());

WinForm 多線程

private void ChangeText(string name) {

            this.textBox1.Text = name;

4.使用System.Action:

WinForm 多線程

            this.Invoke(new Action&lt;string&gt;(this.ChangeText), o.ToString());

WinForm 多線程

本例傳遞一個參數,System.Action有很多個重載,可以無參數(非泛型),而最多可以有四個參數,同樣采用匿名方法,不使用泛型形式的System.Action,如下:

WinForm 多線程

            this.Invoke(new Action(delegate() {

                this.textBox1.Text = o.ToString();

5.使用System.Func

如果Invoke調用主窗體操作之後,還希望在調用完得到一個傳回值:

WinForm 多線程

            System.Func&lt;string, int&gt; f = new Func&lt;string, int&gt;(this.GetId);

            object result = this.Invoke(f,o.ToString());

            MessageBox.Show(result.ToString());

WinForm 多線程

private int GetId(string name) {

            if (name == "Guozhijian") {

                return 999;

            }

            else {

                return 0;

result的值為 999。

System.Func同樣有很多泛形重載,這裡不贅述。

6.關于Invoke的擁有者:Control

本文例中都是用this來引用,這裡this替換為窗體任何一個控件的句柄都是OK的,因為Control.Invoke含義是将方法委托給擁有該Control的線程去執行。