天天看點

多線程通路控件

先看這樣的一個例子:

多線程通路控件

點選"多線程通路"按鈕标簽中文本"此标簽被另一個線程設定文本"會變為"Hello"!

代碼是這樣寫的:

/// <summary>

/// 設定标簽的文本

/// </summary>

private void SetLableText()

{

     this.label1.Text = "Hello!";

}

 /// <summary>

/// 設定标簽的按鈕事件

/// <param name="sender"></param>

/// <param name="e"></param>

private void button1_Click(object sender, EventArgs e)

     System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.SetLableText));

     setLabelTextThread.Start();    

按照想法,這個功能是完成了,運作.點選按鈕,卻出現了異常:

多線程通路控件

分析:label标簽控件是主線程建立的,不能直接從另一個線程通路.可以這樣認為:不能跨線程直接通路控件;

如何才能實作這個功能呢?

在.NET中,所有的控件都是從System.Windows.Forms.Control類派生,Control類提供了一個Invoke()方法,用于在建立控件的線程中通路線程.它的定義如下:

public Object Invoke(Delegate method);

它的參數為一個委托,代表建立控件的線程中要執行的方法.

可以利用這個方法來實作這個功能.

首先定義一個委托:

public delegate void setLabelTextDelegate();//定義一個setLabelTextDelegate()的委托

在定義一個委托變量:

private setLabelTextDelegate setLabelText;

在窗體的構造函數中給這個委托變量初始化:

public Form1()

 {

       InitializeComponent();

       this.setLabelText = this.SetLableText;//SetLableText為上面的"設定标簽的文本"的方法

 }

然後在定義一個方法.方法裡使用Invoke

private void ThreadMethod()

       this.label1.Invoke(this.setLabelText);//setLabelText為上面定義的委托變量

接着把按鈕事件裡的代碼修改一下:

        /// 設定标簽的按鈕事件

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void button1_Click(object sender, EventArgs e)

        {

            System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.SetLableText));//這個方法修改為ThreadMethod,即:

// System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.ThreadMethod));

            setLabelTextThread.Start();

        }

這個就OK了,運作.點選:

多線程通路控件

功能實作:

多線程通路控件

不過"設定标簽的文本"的方法SetLableText()是沒有參數的,在很多情況下,我們寫的方法都是需要參數的,下面我就把這個例子改成有參數的,并示範如何傳遞參數:

首先:改造"設定标簽的文本"的方法SetLableText()變成有參數的:

private void SetLableText(string info)

     this.label1.Text = info;

既然這個方法有參數了,與它對應的委托應該使用參數:

public delegate void setLabelTextDelegate(string infor);

定義的委托變量還是在構造函數中初始化,這個不用改變什麼:

       this.setLabelText = this.SetLableText;

既然使用了參數,那麼Invoke()這個方法應該會有重載的方法吧?

對Invoke()這個方法是有重載的,它的定義如下:

public Object Invoke(Delegate method,param Object [] args);

第二個參數是一個object的數組,就意味着,可以把需要傳遞的參數放到這個數組裡面來進行傳遞

對ThreadMethod()改造:

private void ThreadMethod(Object info)

        this.label1.Invoke(this.setLabelText, new object[] { info});

注意紅色部分,為添加的參數

最後是按鈕事件的改造了:

            System.Threading.Thread setLabelTextThread = new System.Threading.Thread(this.ThreadMethod);

            setLabelTextThread.Start("Hello!");

改造成功:

多線程通路控件

跨線程通路控件步驟可以總結一下:

(1)将通路的控件代碼封裝為一個方法;

(2)根據方法自定義一個對應委托;

(3)增加一個定義的委托類型的字段,并把前面通路控件的方法"挂接"到此字段中;

(4)編寫一個線程方法,在此方法中調用要通路控件的Invoke方法,并把定義好了的委托字段做為參數傳入.

(5)在合适的地方建立線程并啟動運作