none
該如何使用跨執行緒呼叫委派事件?? RRS feed

  • 一般討論

  • 大家好:

    小弟我有一個問題想請教

     

    我想要利用委派的方式

    由SerilPort的DataReceive事件呼叫Timer_Tick事件

    請問該怎麼做?

    煩請各位解答我的疑惑

    謝謝大家~~!

     

    使用環境為: VS2008  Windows Form    C++ .net FrameWork 3.5

    2010年12月21日 下午 04:23

所有回覆

  • 如果你的Timer事件的委派函式內容不會去更動到UI執行緒上的控制項之類的

    不要用Forms.Timer

    改用 System.Timers.Timer 或 Threading.Timer (事實上我很少用Forms.Timer)

    委派的部份你可以參考論壇既有討論

    http://social.msdn.microsoft.com/Search/zh-TW/?Refinement=112&query=%E8%B7%A8%E5%9F%B7%E8%A1%8C%E7%B7%92%E5%A7%94%E6%B4%BE

    http://www.dotblogs.com.tw/billchung/archive/2009/04/12/7981.aspx


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2010年12月22日 上午 04:24
    版主
  • 因為手頭上沒有硬體可以模擬serialport_DataReceived事件,

    所以我試著用 backgroundWorker_DoWork 次執行緒事件代替serialport_DataReceived事件來呼叫timer_Tick事件,

    timer_Tick事件裡面是將int變數a每隔1秒加1,然後秀在label上。
    不過因為backgroundWorker_DoWork事件不會像serialport_DataReceived事件一樣
    (接收到資料後)自動啟動,

    所以我用button_Click事件來觸發backgroundWorker_DoWork事件。

    程式的流程順序概述如下:
    1. 建立委派型別及其物件A。
    2. 建立被委派方法B(呼叫timer1->Start()方法)。
    3. 建立子類別C,該類別需傳入Form型別物件作為參數,
     並建立一公開方法D呼叫(Invoke)傳入物件內之委派型別物件A。
    4. 建立button_Click事件,指定委派型別物件A代理之被委派方法B;
     並啟動次執行緒。
    5. 次執行緒以子類別C傳入目前視窗物件(Form1)作為參數後樣例物件E,
     並以該物件E呼叫子類別內之方法D;
     該方法D間接呼叫(Invoke)Form1內之委派型別物件A。
    6. 實作timer_Tick事件內容。

    實作後的程式是可以運作的,或許可以當作個參考...

    實作中所遇到的問題,
    在於CPP委派方法似乎不能呼叫「同一類別」內之方法!!?
    (試過C#,沒有遇到過這個問題...)
    必須先建立另一類別,然後再透過該類別樣例之物件呼叫(Invoke)目前類別內之委派(delegate)事件...
    因為試了好幾次,只要呼叫同一類別內的委派方法,
    就算compiler沒問題,畫面不會動就是不會動...
    後來參考MSDN內的寫法,幾乎清一色都是另外建立class來呼叫,
    所以只好另外寫class...然後也真的就給它動了...
    不過,因為網路上找不到相關理論證實我的想法,
    所以僅能代表我個人的實作經驗,
    至於事實真相...就有賴高人另外去證實了...
    希望有些參考價值~

    完整程式碼如下(以 vs2010 .Net FrameWork 4.0 撰寫):

    namespace CplusThreadTest {

     using namespace System;
     using namespace System::ComponentModel;
     using namespace System::Collections;
     using namespace System::Windows::Forms;
     using namespace System::Data;
     using namespace System::Drawing;
     using namespace System::Threading;

     /// <summary>
     /// Form1 的摘要
     /// </summary>

     public ref class Form1 : public System::Windows::Forms::Form
     { 

     public:
      Form1(void)
      {
       InitializeComponent();
       //
       //TODO: 在此加入建構函式程式碼
       //
      }

     protected:
      /// <summary>
      /// 清除任何使用中的資源。
      /// </summary>
      ~Form1()
      {
       if (components)
       {
        delete components;
       }
      }
     private: System::Windows::Forms::Button^  button1;
     protected:
     private: System::Windows::Forms::Label^  label1;
     private: System::Windows::Forms::Timer^  timer1;
     private: System::ComponentModel::BackgroundWorker^  backgroundWorker1;
     private: System::ComponentModel::IContainer^  components;

     private:
      /// <summary>
      /// 設計工具所需的變數。  
      /// </summary>


    #pragma region Windows Form Designer generated code
      /// <summary>
      /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器
      /// 修改這個方法的內容。
      /// </summary>
      void InitializeComponent(void)
      {
       this->components = (gcnew System::ComponentModel::Container());
       this->button1 = (gcnew System::Windows::Forms::Button());
       this->label1 = (gcnew System::Windows::Forms::Label());
       this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
       this->backgroundWorker1 = (gcnew System::ComponentModel::BackgroundWorker());
       this->SuspendLayout();
       //
       // button1
       //
       this->button1->Location = System::Drawing::Point(102, 190);
       this->button1->Name = L"button1";
       this->button1->Size = System::Drawing::Size(75, 23);
       this->button1->TabIndex = 0;
       this->button1->Text = L"button1";
       this->button1->UseVisualStyleBackColor = true;
       this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
       //
       // label1
       //
       this->label1->AutoSize = true;
       this->label1->Location = System::Drawing::Point(102, 83);
       this->label1->Name = L"label1";
       this->label1->Size = System::Drawing::Size(11, 12);
       this->label1->TabIndex = 1;
       this->label1->Text = L"0";
       //
       // timer1
       //
       this->timer1->Interval = 1000;
       this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
       //
       // backgroundWorker1
       //
       this->backgroundWorker1->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &Form1::backgroundWorker1_DoWork);
       //
       // Form1
       //
       this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
       this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
       this->ClientSize = System::Drawing::Size(284, 262);
       this->Controls->Add(this->label1);
       this->Controls->Add(this->button1);
       this->Name = L"Form1";
       this->Text = L"Form1";
       this->ResumeLayout(false);
       this->PerformLayout();

      }
    #pragma endregion

     static int a = 0;

     // 1.建立委派型別myMethodDelegate及其物件myDelegate
     public:
      delegate void myMethodDelegate(); 
      myMethodDelegate^ myDelegate;

     // 2.建立被委派呼叫方法testThread
     void testThread(){
      timer1->Start();
     }

     // 3.建立呼叫委派類別myThreadClass,樣例物件時需傳入Form類別作為參數
     ref class myThreadClass{
     // 3.1.建立Form類別物件myForm1
     private:
      Form1^ myForm1;
     // 3.2.製作建構子,將樣例物件所傳入之Form類別參數指定至myForm1物件
     public:
      myThreadClass(Form1^ myForm){
       myForm1 = myForm;
      }
     // 3.3.呼叫傳入Form類別內的委派物件
     void Run(){
      myForm1->Invoke(myForm1->myDelegate);
     }
     }; 

     // 4.透過button click事件呼叫多執行緒事件
     private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
         // 4.1.利用委派型別myMethodDelegate建立委派事件呼叫testThread事件
         myDelegate = gcnew myMethodDelegate(this, &Form1::testThread);
         // 4.2.啟動另一執行緒
         backgroundWorker1->RunWorkerAsync();
        }

     // 5.利用多執行緒事件呼叫委派事件
     //(以backgroundWorker_DoWork代表serialport::DataReceived事件)
     private: System::Void backgroundWorker1_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e) {
         // 5.1.以步驟3之呼叫委派類別樣例物件,並傳入目前視窗類別
         myThreadClass^ myThreadClass1 = gcnew myThreadClass(this);
         // 5.2.以該類別內之Run方法呼叫目前視窗內之委派事件
         myThreadClass1->Run();
        }

     //timer_Tick事件
     private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
         a++;
         label1->Text = Convert::ToString(a);
        } 
    };
    }

    2010年12月26日 下午 04:05
  • 請問你的問題解決了嗎 ?

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2011年1月1日 下午 04:34
    版主