WinForm程序界面假死,尋求完美解決方案

   故事的開端是這樣的,小白是一個程序員,他確實也是一個小白,目前還在程序員發展的道路上,兢兢業業的當心求學。程序員

   有一天,小白接到一個任務,完成一個Winform程序,附加一個功能就是能夠讀IC卡。異步

   小白終於有機會一展身手了!!難免心裏興奮。ide

   再聯繫了IC卡廠家,拿到開發SDK後,小白不久就碰到了如下難題:this

   一、廠家的讀卡器是經過API給定的事件ReadCard()驅動的,而讀卡器在ReadCard事件驅動之後,能夠在日後的3s之內偵測是否有IC卡片在附近:spa

       (1)3s內,有IC卡在設備附近,當即讀卡,返回讀卡狀態。線程

       (2)3s內若是沒有IC卡在設備附近,則讀卡器等待3s後返回「-3」表示無卡。code

   二、小白在程序中,對讀卡器獲取的值須要作進一步處理,如Winform登陸。orm

   小白是這樣構想實現他的程序的:blog

    一、設定一個定時器。定時器定時的驅動讀卡設備進行讀卡。事件

    二、獲取讀卡結果之後,在對界面上的內容進行更新。

   小白按照這樣的思路寫了這樣的代碼

private void FormLogin_Load(object sender, EventArgs e)
{
         TimerCallback readerDelegate = new TimerCallback(CardReaderDoing);//設定託管
           var task2 = System.Threading.Tasks.Task.Factory.StartNew(new Action(() =>
            {
                try
                {
                    int initCOM = InitCardThird();
                    if (0 == initCOM)
                    {
                       // 讀卡器讀卡流程爲3s,這裏設置3.5s讀卡一次
                      readerTimer = new System.Threading.Timer(readerDelegate, null, 1000, 3500);
                    }
                    else
                    {
                        string err = "打開串口異常" + initCOM.ToString();
                        InvokeHelper.Set(label_tips, "Visible", true);
                        InvokeHelper.Set(label_tips, "Text", err);
                        InvokeHelper.Set(label_tips, "ForeColor", Color.Red);
                    }
                }
                catch (Exception ex)
                {
                    string strDateInfo = "出現應用程序未處理的異常:" + DateTime.Now.ToString() + "\r\n";
                    string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆棧信息:{1}", ex.Message, ex.StackTrace);
                    log.Error(str);
                }
            }));
}

接下來是定時事件中小白的處理方法:

private void CardReaderDoing(object stateinfo)
 {
          try
            {
                int retCode = obj.ReadCard();if (1 == retCode)
                {
                    //刷卡成功beep
                    obj.Extsys_BeepOK();
                    readerTimer.Change(-1, -1);
                    string studentCode = obj.GetCardNo();
                    string userName = obj.GetName();

                    UserInfo.StudentCode = studentCode;
                    UserInfo.StudentName = userName;

                    UserInfo.AuthToken = CommonHelper.WebMethod.GetAutherizeToken(BaseConfigInfoProvider.ConfigInfo.LeoAppDomain, UserInfo.StudentCode);
                    bool getAuthErrored = CheckObj.CheckErrored(UserInfo.AuthToken);
                    if (getAuthErrored)
                    {
                        string err = CheckObj.CheckAndReturn(UserInfo.AuthToken, "CH");

                        //DialogResult dr = AutoClosedMessageBox.Show(err, "系統提示", 20, 15);
                        AutoClosedMessageBox amb = new AutoClosedMessageBox();
                        DialogResult dr = amb.Show(err, "系統提示", 20, 15);
                        if (dr == DialogResult.OK || dr == DialogResult.Cancel)
                        {
                            //amb.Dispose();
                            /*用戶驗證錯誤後,5s後啓動讀卡器*/
                            readerTimer.Change(5000, 3500);
                            InvokeHelper.Set(label_ReadNO, "Text", "請刷學生卡");
                        }
                    }
                    /*用戶驗證成功*/
                    else
                    {
                        InvokeHelper.Set(label_ReadNO, "Text", studentCode);
                        /*設置最近預定*/
                        GetCurrentSession();
                        InvokeHelper.Set(this, "Visible", false);
                        //顯示主窗體
                            FormMain frm = new FormMain();
                        DialogResult dr = frm.ShowDialog();

                        InvokeHelper.Set(this, "Visible", true);
                        InvokeHelper.Set(label_ReadNO, "Text", "請刷卡");
                        readerTimer.Change(1000, 3500);
                    }
                }
                else if (-3 != retCode)
                {
                    obj.Extsys_BeepERR();
                    string err = CommonHelper.ErrorDefinition.GetErrMsgByCode(retCode);
                    string err_brief = "Code:" + retCode.ToString();
                    InvokeHelper.Set(label_ReadNO, "Text", err);
                    InvokeHelper.Set(label_tips, "Text", err_brief);

                    if (readerTimer != null)
                    {
                        readerTimer.Dispose();
                    }
                }
                else
                {
                    //-3,no card
                }
            }
            catch (Exception ex)
            {
                string strDateInfo = "出現應用程序未處理的異常:" + DateTime.Now.ToString() + "\r\n";
                string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆棧信息:{1}", ex.Message, ex.StackTrace);
                log.Error(str);
            }
 }

小白髮現了大問題!!

因爲讀卡事件來自與第三方SDK,obj.ReadCard()每次調用,若是在無卡狀態下,須要等待3s才能返回讀卡狀態。所以再此出致使了界面阻塞,在運行起來的時候,界面假死了!!

有人告訴小白說,「你應該在 CardReaderDoing事件裏,將obj.ReadCard()事件用異步的方式進行處理!好比用Task或者新開一個線程去處理。」也有人告訴小白說,「你試試委託方式唄!」,小白收到你們幫忙的建議非常開心,可是嘗試完後,小白和小白的夥伴們都驚呆了!答案是:官人,不能夠!!!!

  小白只能怪本身才疏學淺,因而想換個方式試試。BackgroundWork之前小白是用過的,並且能夠經過異步的方式,讓IO和界面UI線程分開?

  因而小白有了下面的代碼:

 

        //初始worker
        private void InitializeBackgoundWorker()
        {
            this.backgroundWorker1.WorkerReportsProgress = true;
            this.backgroundWorker1.WorkerSupportsCancellation = true;
            this.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            //this.backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
            this.backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

       //異步過程處理讀卡
        void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            //get result from card reader
            e.Result = ReadCardResult(worker,e);
            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
        }
        //read card and return result
        private int ReadCardResult(BackgroundWorker worker, DoWorkEventArgs e)
        {
            int retCode = -3;
            retCode = obj.ReadCard();
            return retCode;
        }
        //worker完成
         void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                string strDateInfo = "出現應用程序未處理的異常:" + DateTime.Now.ToString() + "\r\n";
                string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆棧信息:{1}", e.Error.Message, e.Error.StackTrace);
                log.Error(str);
                //MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                 //do nothing
            }
            else
            {
                int retCode =(int)e.Result;
                try
                {
                    if (1 == retCode)
                    {
                        //刷卡成功beep
                        obj.Extsys_BeepOK();
                        readerTimer.Change(-1, -1);
                        string studentCode = obj.GetCardNo();
                        string userName = obj.GetName();

                        UserInfo.StudentCode = studentCode;
                        UserInfo.StudentName = userName;

                        UserInfo.AuthToken = CommonHelper.WebMethod.GetAutherizeToken(BaseConfigInfoProvider.ConfigInfo.LeoAppDomain, UserInfo.StudentCode);
                        bool getAuthErrored = CheckObj.CheckErrored(UserInfo.AuthToken);
                        if (getAuthErrored)
                        {
                            string err = CheckObj.CheckAndReturn(UserInfo.AuthToken, "CH");

                            //DialogResult dr = AutoClosedMessageBox.Show(err, "系統提示", 20, 15);
                            AutoClosedMessageBox amb = new AutoClosedMessageBox();
                            DialogResult dr = amb.Show(err, "系統提示", 20, 15);
                            if (dr == DialogResult.OK || dr == DialogResult.Cancel)
                            {
                                //amb.Dispose();
                                /*用戶驗證錯誤後,5s後啓動讀卡器*/
                                readerTimer.Change(5000, 3500);
                                InvokeHelper.Set(label_ReadNO, "Text", "請刷學生卡");
                            }
                        }
                        /*用戶驗證成功*/
                        else
                        {
                            InvokeHelper.Set(label_ReadNO, "Text", studentCode);
                            /*設置最近預定*/
                            GetCurrentSession();
                            InvokeHelper.Set(this, "Visible", false);
                            //顯示主窗體
                            FormMain frm = new FormMain();
                            DialogResult dr = frm.ShowDialog();

                            InvokeHelper.Set(this, "Visible", true);
                            InvokeHelper.Set(label_ReadNO, "Text", "請刷學生卡");
                            readerTimer.Change(1000, 3500);
                        }
                    }
                    else if (-3 != retCode)
                    {
                        obj.Extsys_BeepERR();
                        string err = CommonHelper.ErrorDefinition.GetErrMsgByCode(retCode);
                        string err_brief = "Code:" + retCode.ToString();
                        InvokeHelper.Set(label_ReadNO, "Text", err);
                        InvokeHelper.Set(label_tips, "Text", err_brief);

                        if (readerTimer != null)
                        {
                            readerTimer.Dispose();
                        }
                    }
                    else
                    {
                        //-3,no card
                    }
                }
                catch (Exception ex)
                {
                    string strDateInfo = "出現應用程序未處理的異常:" + DateTime.Now.ToString() + "\r\n";
                    string str = string.Format(strDateInfo + "Application UnhandledException:{0};\n\r堆棧信息:{1}", ex.Message, ex.StackTrace);
                    log.Error(str);
                }
            }
        }

而小白經過修改定時器裏的代碼是:

 

 private void CardReaderDoing(object stateinfo)
 {
     if (!backgroundWorker1.IsBusy)
     {
         backgroundWorker1.RunWorkerAsync();
     }
 }

小白和他們小夥伴們再次驚呆了!!!界面啓動,仍是由於讀卡器讀卡的問題,界面假死!!

各位大哥、大姐、妹子、帥哥、老道、貧尼們,這是爲蝦米啊!!

小白正在爲此尋找一個完美的解決方案。

各位大哥、大姐、妹子、帥哥、老道、貧尼們,大家別隻是路過!小白請指教了!!

說兩句吧。

相關文章
相關標籤/搜索