[C#] 非同步委派測試(關閉表單時會錯誤)

  • 8451
  • 0
  • 2010-03-15

[C#] 非同步委派測試(關閉表單時會錯誤)

今天在練習非同步委派,這邊隨手記錄一下。這邊使用表單來實作,

雖然表單不會 Lock 住,但在測試時,發現若是直接關閉表單會出現錯誤,

若是在關閉時結束委派作業,不過程式會停在那邊,還找不出原因。

之前在實作 BackgroundWorker ,也遇過相同情形;我在

FormClosing 事件下,取消了背景作業。(程式碼如下)

 

 


//關閉表單發生時
        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            //取消背景作業
            this.CancelBackgroundWork();              
        }  

 

 

在實作非同步委派時,又該如何結束委派作業呢?

查看 msdn 的說明,使用 EndBegin() 函式,卻使程式當住。

 

程式碼範例

 


//引用命名空間
using System.Runtime.Remoting.Messaging;

namespace CallBackDemo {
    public partial class Form1 : Form {

        //宣告委派型別
        private delegate string _del(string value,Control ctl);
        private delegate void _del2(string value, Control ctl);

        //宣告委派變數
        private _del Mydel = null;
        private IAsyncResult MyAsyncReseult = null;
        private AsyncCallback MyCallback = null;
        public Form1() {
            InitializeComponent();            
        }

        private void Form1_Load(object sender, EventArgs e) {            
        }

        private void btnStart_Click(object sender, EventArgs e) {
            btnStart.Enabled = false;
            //建立委派物件            
            Mydel = new _del(DoUpdate);
            //建立 Callback 物件
            MyCallback = new AsyncCallback(CallBackMethod);            
            //執行非同步委派,主執行緒會繼續往下走
            MyAsyncReseult = Mydel.BeginInvoke("1", textBox1, MyCallback, null);
            
        }

        //更新資料
        private string DoUpdate(string value, Control ctl) {
            int iNumber = int.Parse(value);
            while (true) {
                iNumber++;
                UpdateUI(iNumber.ToString(), textBox1);
                if (iNumber == 100000){
                    break;
                }
            }
            return iNumber.ToString();
        }

        private void UpdateUI(string value, Control ctl) {
            //判斷是否 [非] UI 執行緒
            if (this.InvokeRequired) {
                _del2 myUpdate = new _del2(UpdateUI);

                //強制使用 UI 執行緒來執行委派
                if (!this.IsDisposed) {
                    this.Invoke(myUpdate, value, ctl);
                } else { return; }
            } else {
                ctl.Text = value;
            }
        }

        //當委派執行完成後,會回呼這個函式
        private void CallBackMethod(IAsyncResult ar) {
            //這邊執行其他作業
            //......
            //......


            //結束 Callback
            //取得叫用時委派物件
            _del callback = (_del)((AsyncResult)ar).AsyncDelegate;
            //完成非同步呼叫
            string sResult = callback.EndInvoke(ar);                                    
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            Mydel.EndInvoke(MyAsyncReseult);
            MyAsyncReseult.AsyncWaitHandle.Close();
        }          
    }
}

 

懷疑是否與傳入的 callback 委派有關?

不過還是無法解決 = = 。

 

輸出

2010-01-14_204116

 

程式碼屍體 CallBackDemo.rar

 

<<後記>>

感謝 Bill Chung 大的提點,提供連結 http://www.dotblogs.com.tw/billchung/archive/2009/04/04/7851.aspx

還原問題:

當我點選關閉表單時,應該是要順利的關閉應用程式,不過因為使用非同步委派,產生了另外一條執行緒去執行更新表單的作業,

這時,當我按下關閉,當執行緒要去更新表單時,就會出現錯誤,如圖

2010-01-16_113956

 

我嘗試在程式中加入

 


this.IsDisposed

 

依然無效。最後參考 Bill Chung 大的程式碼範例,程式加入 try catch 濾掉例外,程式即可順利關閉


	try {
                    if (!this.IsDisposed) {
                        this.Invoke(myUpdate, value, ctl);
                    } else { return; }
                }
                catch (ObjectDisposedException objex) {
                    //不做任何處理
                }
                catch (ThreadAbortException aboex) {
                    //不做任何處理
                }

 

程式碼下載 CallBackDemo.rar

三小俠  小弟獻醜,歡迎指教