WinForms程序使用委託(Invoke)的方式操作界面的控件

在WinForms程序開發中,有時使用多線程或者異步處理比較耗時的數據,處理完成後需要把結果反饋到程序界面上,這是就需要操作WinForms程序的界面控件了。

如果直接操作的話,則會出現以下錯誤

注:這個異常來源於.NET2的一個限制:工作線程不能訪問窗口線程創建的控件。


線程間操作無效: 從不是創建控件“updateMaterial”的線程訪問它。




解決方法有兩種:

方法一:是在窗口線程中設置CheckForIllegalCrossThreadCalls = false (不推薦

比如窗口中有一個button1,我要新建一個線程訪問到button1。

this.button1.Enabled = false;
new Thread(new ThreadStart(delegate()
{
    try {
       
        CheckForIllegalCrossThreadCalls = false;
        // 直接設置會引發異常:線程間操作無效,從不創建控件的線程訪問它
        this.button1.Enabled = true;
    }catch(Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
                
})).

方法二:使用委託的方式Invoke操作界面的控件(推薦

private delegate void _SetButtonState(Button button,bool state);
private void SetButtonState(Button button,bool state) 
{
    // 對於該控件的請求來自於創建該控件所在線程以外的線程
    if (button.InvokeRequired)
    {
        _SetButtonState _set = new _SetButtonState(delegate(Button _button, bool _state)
            {
                _button.Enabled = _state;
            });
        this.Invoke(_set, button, state);
    }
    else 
    {
        button.Enabled = state;
    }
} 

創建一個線程調用這個委託

this.button1.Enabled = false;
new Thread(new ThreadStart(delegate()
{
    try {
        // 直接設置會引發異常:線程間操作無效,從不創建控件的線程訪問它
        // CheckForIllegalCrossThreadCalls = false;
        // this.button1.Enabled = true;
        // 用委託的方式
        SetButtonState(button1,true);
    }catch(Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
                
})).Start();


另外,附上一個修改的更爲直接的Invoke函數

	private delegate void _SetListData();
        private void SetListData()
        {
            _SetListData _set = new _SetListData(delegate()
            {
                this.t_material_infoTableAdapter.Fill(this.materialDataSet.t_material_info);
            });
            this.Invoke(_set);
        } 


調用委託用這個:

SetListData();


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