2013-01-16 22 views
0

我在更新多個類的UI組件時遇到問題。 我已經宣佈了兩個類。 第一個是包含GUI/UI文本框的ClassMain。我還宣佈了一個叫ClassTwo的第二課。 ClassTwo的一個實例在主類中聲明。受管理的C++/CLI .net使用線程更新來自不同類的GUI組件/文本框

爲了進一步複雜化情景,我在方程中添加了線程。大家都知道線程是有用的,因爲它們阻止了GUI的鎖定並進一步增強了CPU吞吐量。 我所追求的是一個解決方案,安全地更新這兩個類也是線程安全的文本框。 目前我不知道如何從ClassTwo訪問textBox1,所以我也很想看到這個解決方案。 我附上我的代碼下面(沒有文本框更新,因爲我不確定如何做到這一點)。
任何幫助讚賞。 謝謝。

#pragma once 

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; 

ref class ClassTwo 
{ 
public: 
    ClassTwo(void); 
    void DoProcessing(void); 
}; 

public ref class ClassMain : public System::Windows::Forms::Form 
{ 
public: //Constructor of Main Class 
    ClassMain(void) 
    { 
      InitializeComponent(); 
      backgroundWorker1->RunWorkerAsync(); 
      backgroundWorker2->RunWorkerAsync(); 
    } 

protected: 
    ~ClassMain() //Deconstructor of main class 
    { 
     if (components) 
     { 
      delete components; 
     } 
    } 
private: System::Windows::Forms::TextBox^ textBox1; 
private: System::ComponentModel::Container ^components; 
//Decleare 2 background Worker threads to perform our calculation and logicwork 
//One will execute work through through ClassMain the other using ClassTwo's method of DoProcessing 
private: System::ComponentModel::BackgroundWorker^ backgroundWorker1; 
private: System::ComponentModel::BackgroundWorker^ backgroundWorker2; 
void backgroundWorker1_DoWork(Object^ sender, DoWorkEventArgs^ e); 
void backgroundWorker2_DoWork(Object^ sender, DoWorkEventArgs^ e); 

//Declare an instance of Class Two 
private: ClassTwo^ myclass2; 


    void InitializeComponent(void) 
    { 
     this->textBox1 = (gcnew System::Windows::Forms::TextBox()); 
     this->SuspendLayout(); 
     this->textBox1->Location = System::Drawing::Point(42, 61); 
     this->textBox1->Multiline = true; 
     this->textBox1->Name = L"textBox1"; 
     this->textBox1->Size = System::Drawing::Size(409, 71); 
     this->textBox1->TabIndex = 0; 

     this->backgroundWorker1 = (gcnew System::ComponentModel::BackgroundWorker()); 
     this->backgroundWorker1->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &ClassMain::backgroundWorker1_DoWork); 

     this->backgroundWorker2 = (gcnew System::ComponentModel::BackgroundWorker()); 
     this->backgroundWorker2->DoWork += gcnew System::ComponentModel::DoWorkEventHandler(this, &ClassMain::backgroundWorker2_DoWork); 
     // 
     // Form1 
     // 
     this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); 
     this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; 
     this->ClientSize = System::Drawing::Size(507, 189); 
     this->Controls->Add(this->textBox1); 
     this->Name = L"Form1"; 
     this->Text = L"Form1"; 
     this->ResumeLayout(false); 
     this->PerformLayout(); 
    } 
}; 

void ClassMain::backgroundWorker1_DoWork(Object^ sender, DoWorkEventArgs^ e) 
{ 
    this->myclass2->DoProcessing(); 
} 

void ClassMain::backgroundWorker2_DoWork(Object^ sender, DoWorkEventArgs^ e) 
{ 
    int j; 
    for (j=0;j<10000;j++) 
    { 
     //Write the output to our textbox backgroundWorker1 
     //this->textBox1->AppendText("Hello From ClassMain: The Value of j is" + j.ToString() + "\r\n"); 
    } 
} 

//Constructor of ClassTwo 
ClassTwo::ClassTwo(void) 
{ 
} 
//DoProcessing of ClassTwo 
void ClassTwo::DoProcessing(void) 
{ 
    int i; 
    for (i=0;i<10000;i++) 
    { 
     //Write the output from ClassTwo to our common textbox from backgroundWorker2 
     //this->textBox1->AppendText("Hello From Class 2: The Value of i is" + i.ToString() + "\r\n"); 
    } 
} 


[STAThreadAttribute] 
int main(array<System::String ^> ^args) 
{ 
    // Enabling Windows XP visual effects before any controls are created 
    Application::EnableVisualStyles(); 
    Application::SetCompatibleTextRenderingDefault(false); 

// Create the main window and run it 
    Application::Run(gcnew ClassMain()); 
    return 0; 
} 
+0

由於Win32的工作方式,您不能直接從不同於創建它的線程訪問文本框控件 - 但您可以在擁有的窗體上使用BeginInvoke進行研究,該窗體基本上會封裝方法調用到GUI線程上。 – Cameron

+0

謝謝卡梅隆, 我已經看到了begininvoke和調用,但不明白如何使ClassTwo的DoProcessing()中的文本框的更新? –

回答

1

呼叫textBox1->的BeginInvoke(...)textBox1->調用(...)。 BeginInvoke/Invoke是所有控件繼承的Control類的方法。

+0

您是如何在ClassTwo的DoProcessing()方法中做到這一點的?如果它不擁有文本框或可以直接訪問它? –

1

製作一個新的Windows窗體應用程序並將其粘貼到Form1構造函數的正下方。

public void InvokeSafely(Control control, Action action) 
    { 
     if (control.InvokeRequired) 
      control.BeginInvoke(action); 
     else 
      action(); 
    } 

    public void RunsInAnotherThread(object dummy) 
    { 
     InvokeSafely(this,() => Text = "I made the title change safely"); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     ThreadPool.QueueUserWorkItem(RunsInAnotherThread); 
    } 

它演示瞭如何使用BeginInvoke在GUI線程上運行委託。

相關問題