多線程訪問控制項

來源:互聯網
上載者:User

先看這樣的一個例子:

點擊"多線程訪問"按鈕標籤中文本"此標籤被另一個線程設定文本"會變為"Hello"!
代碼是這樣寫的:
/// <summary>
/// 設定標籤的文本
/// </summary>
private void SetLableText()
{
     this.label1.Text = "Hello!";
}
 /// <summary>


/// 設定標籤的按鈕事件
/// </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>
        /// 設定標籤的按鈕事件
        /// </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()變成有參數的:
/// <summary>
/// 設定標籤的文本
/// </summary>
private void SetLableText(string info)
{
     this.label1.Text = info;
 }
既然這個方法有參數了,與它對應的委託應該使用參數:
public delegate void setLabelTextDelegate(string infor);

定義的委託變數還是在建構函式中初始化,這個不用改變什麼:
public Form1()
 {
       InitializeComponent();
       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});
 }
注意紅色部分,為添加的參數
最後是按鈕事件的改造了:

/// <summary>
        /// 設定標籤的按鈕事件
        /// </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(this.ThreadMethod);
            setLabelTextThread.Start("Hello!");
           
        }

改造成功:

跨線程訪問控制項步驟可以總結一下:
(1)將訪問的控制項代碼封裝為一個方法;
(2)根據方法自訂一個對應委託;
(3)增加一個定義的委託類型的欄位,並把前面訪問控制項的方法"掛接"到此欄位中;
(4)編寫一個線程方法,在此方法中調用要訪問控制項的Invoke方法,並把定義好了的委託欄位做為參數傳入.
(5)在合適的地方建立線程並啟動運行

本人的第一篇博文.所寫的都是雕蟲小技,不足掛齒.只是希望把自己的心得分享出來.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.