2011-08-15 39 views
0

当窗体上单击一个按钮时,我有一个运行测试的Windows窗体EngTest_F()。这个函数是从本地DLL中调用的。我还在托管表单代码中创建了一个后台工作,该代码调用函数GetSicStatusMsg来更新表单中的文本框。从Visual C++中的非托管代码更新托管窗体

在我的本地EngTest_F函数中,我有将文本更新推送到字符串队列的函数。然后,当GetSicStatusMsg被调用时,它会检查队列中的字符串并将它们打印到窗体中的richTextBox中。

我需要做的是让背景工作者连续运行GetSicStatusMsg,以便测试运行的实时进度。实际发生的事情是EngTest_F运行,然后在完成后大约一秒钟,所有状态消息都会立即打印出来。

有没有办法完成我想要做的事情?还是有更简单的方法?这是我第一次使用线程,文档有点欠缺。

private: void GetSicStatusMsg() 
     { 
      try 
      { 
       while(GetNumStatusMsgs()) 
       { 
        String^ Status = gcnew String(GetStatusMsg().c_str()); 
        DisplayStatus(Status, DISPLAY_SIC); 
       } 
      } 
      catch(SIC_Error *Err) 
      { 
       if(Err->ErrorCode != NO_CONTROLLER) 
       { 
        String^ Error = gcnew String(Err->ErrorMsg.c_str()); 
        DisplayStatus(Error,DISPLAY_SIC); 
       } 
      } 
      catch(Exception ^Ex) 
      { 
       DisplayStatus(Ex->Message,DISPLAY_SIC); 
      } 
     } 

    private: System::Void button1_Click(System::Object^ /*sender*/, System::EventArgs^ /*e*/) 
     {  
      this->button1->Enabled = false; 

      // Enable the Cancel button while 
      // the asynchronous operation runs. 
      this->button4->Enabled = true; 

      // Start the asynchronous operation. Needs to be running while EngTest_F is running 
      backgroundWorker1->RunWorkerAsync(); 

      EngTest_F(); 
     } 

    private: System::Void backgroundWorker1_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e) 
     { 
      GetSicStatusMsg(); 
     } 

    private: void backgroundWorker1_RunWorkerCompleted(Object^ sender, RunWorkerCompletedEventArgs^ e) 
     { 
      // Enable the Start button. 
      button1->Enabled = true; 

      // Disable the Cancel button. 
      button4->Enabled = false; 
     } 

    private: void backgroundWorker1_DoWork(Object^ sender, DoWorkEventArgs^ e) 
     { 
      // Get the BackgroundWorker that raised this event. 
      BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender); 

      worker->ReportProgress(0); 
     } 
+0

您可能经常调用ReportProgress(),导致UI线程充斥着调用请求,因此它不再适应其正常职责。通过添加System :: Threading :: Thread :: Sleep(50)来检查它。在ReportProgress调用之后。如果能够解决这个问题,那么就会以人眼可以感知的速度报告进度。每秒不超过20次。 –

回答

0

看起来好像你的代码是向后的。 UI线程应该更新UI,后台线程应该执行长时间运行的任务(我想这就是EngTest_F())。解决这个问题的一种方法是使用System.Windows.Forms.Timer组件。设置Interval = 50左右的计时器,调用GetSicStatusMsg()更新UI。任务启动时启用计时器,并在任务完成时将其禁用。我不是BackgroundWorker的专家(我倾向于使用普通的Thread对象),但我敢打赌,只要任务进行,就需要调用ReportProgress;您的代码只能调用一次ReportProgress。我建议在你的情况下使用一个普通的Thread +一个Timer,因为你的非托管代码可能很难调用BackgroundWorker.ReportProgress()。

+0

我认为你是对的,制作一个自定义线程看起来像要走的路 - 背景工作者比方便更麻烦 –

+0

知道了!我最终做的是创建两个线程,一个用于EngTest_F,一个用于GetSicStatusMsg。为了在EngTest_F完成后停止GetSicStatusMsg线程,我刚刚创建了一个布尔变量'test_finished',它在EngTest_F完成时设置为true。然后我使用test_finished作为GetSicStatusMsg中while循环中的不变量,所以它运行到test_finished = true –