淺述WinForm多線程編程與Control.Invoke的應用

VS200八、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
    衆所周知,新開一個線程代價是很高昂的,若是咱們每一個操做都新開一個線程,那麼太浪費了,因而,下面使用線程池。
    無參數傳遞:
    this

private void DoWork()  {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomething));
        }
        private void DoSomething(object o) {
            MessageBox.Show("thread start");
        }

    有參數傳遞:
    spa

private void DoWork()  {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoSomething), "guozhijian");
        }
        private void DoSomething(object o) {
            MessageBox.Show(o.ToString());
        }

    使用匿名方法更靈活:
    線程

private void DoWork()  {
            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.使用自定義委託orm

private void DoWork()  {
            WaitCallback wc = new WaitCallback(this.DoSomething);
            ThreadPool.QueueUserWorkItem(wc, "Guozhijian");
        }

        private delegate void MyInvokeDelegate(string name);
        private void DoSomething(object o) {
            this.Invoke(new MyInvokeDelegate(this.ChangeText), o.ToString());
        }

        private void ChangeText(string name) {
            this.textBox1.Text = name;
        }

哦,太麻煩了,難道我每次都要定義一個委託啊,這樣可不行。

4.使用System.Action:blog

private void DoWork()  {
            WaitCallback wc = new WaitCallback(this.DoSomething);
            ThreadPool.QueueUserWorkItem(wc, "Guozhijian");
        }

        private void DoSomething(object o) {
            this.Invoke(new Action<string>(this.ChangeText), o.ToString());
        }

        private void ChangeText(string name) {
            this.textBox1.Text = name;
        }

本例傳遞一個參數,System.Action有不少個重載,能夠無參數(非泛型),而最多能夠有四個參數,一樣採用匿名方法,不使用泛型形式的System.Action,以下:開發

private void DoWork()  {
            WaitCallback wc = new WaitCallback(this.DoSomething);
            ThreadPool.QueueUserWorkItem(wc, "Guozhijian");
        }

        private void DoSomething(object o) {
            this.Invoke(new Action(delegate() {
                this.textBox1.Text = o.ToString();
            }));
        }


5.使用System.Func
若是Invoke調用主窗體操做以後,還但願在調用完獲得一個返回值:string

private void DoWork()  {
            WaitCallback wc = new WaitCallback(this.DoSomething);
            ThreadPool.QueueUserWorkItem(wc, "Guozhijian");
        }

        private void DoSomething(object o) {
            System.Func<string, int> f = new Func<string, int>(this.GetId);
            object result = this.Invoke(f,o.ToString());
            MessageBox.Show(result.ToString());
        }

        private int GetId(string name) {
            this.textBox1.Text = name;
            if (name == "Guozhijian") {
                return 999;
            }
            else {
                return 0;
            }
        }


result的值爲 999。
System.Func一樣有不少泛形重載,這裏不贅述。

6.關於Invoke的擁有者:Control
本文例中都是用this來引用,這裏this替換爲窗體任何一個控件的句柄都是OK的,由於Control.Invoke含義是將方法委託給擁有該Control的線程去執行。it

相關文章
相關標籤/搜索