Problem mit thread-übergreifendem Zugriff auf Label
-
Hi
Ich habe eine vielleicht unübliche Lösung, um in einem Form den Fortschritt einer Initialisierungsfunktion darzustellen.
Folgender Aufbau:
Dialog_WaitSomethingIsDone - Dialog zum Anzeigen, ganz normale Windows Forms Dialog
Class_WaitSomethingIsDone - Klasse zum Verwalten des DialogesClass_WaitSomethingIsDone::Class_WaitSomethingIsDone(void) { m_StatusDialog=gcnew Dialog_WaitSomethingIsDone(); m_BackgroundWorker=gcnew System::ComponentModel::BackgroundWorker(); m_BackgroundWorker->DoWork+=gcnew System::ComponentModel::DoWorkEventHandler(this,&Class_WaitSomethingIsDone::BackGroundWoker_DoWork); m_BackgroundWorker->WorkerSupportsCancellation=true; } void Class_WaitSomethingIsDone::Start() { m_BackgroundWorker->RunWorkerAsync(m_StatusDialog); } void Class_WaitSomethingIsDone::Stop() { m_StatusDialog->Close(); m_BackgroundWorker->CancelAsync(); } void Class_WaitSomethingIsDone::SetWindowText(System::String^ t) { m_StatusDialog->DialogText=t; } void Class_WaitSomethingIsDone::IncProgressBar() { m_StatusDialog->ProgressBarValue++; } void Class_WaitSomethingIsDone::SetProgressBar(int wert) { m_StatusDialog->ProgressBarValue=wert; } void Class_WaitSomethingIsDone::SetText(System::String^ t) { m_StatusDialog->LabelText=t; } void Class_WaitSomethingIsDone::BackGroundWoker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { //startet den Dialog System::Windows::Forms::Form^ temp=dynamic_cast<System::Windows::Forms::Form^>(e->Argument); temp->ShowDialog(); }
Wie ihr seht, erstelle ich im Konstruktor den Dialog , und den BackgroundWorker.
Bei Start wird der BackgroundWorker gestartet, der den Dialog anzeigt.
Dadurch kann der aufrufende Thread weiterarbeiten, und über die anderen Funktionen die Ansicht steuern. Außerdem ist der Focus trotzdem immer auf dem Dialog.Verständlicherweise kommt dann eine InvalidOperationException
Nach ein bißchen googeln und hier im Forum suchen, habe ich dann eine Lösung mit delegates implementiert bzw. ehrlich gesagt abgeschrieben
Beispielcode in Dialog_WaitSomethingIsDone:
private: delegate void SetLableDelegate(String^ text2); void UpdateTextBox(System::String^ t) { try { this->label1->Text=t; } catch(...) { System::Windows::Forms::MessageBox::Show("Fehler bei setlabeltext"); } } public: property System::String^ LabelText { void set(String^ t) { if(label1->InvokeRequired) { SetLableDelegate^ callBack; callBack=gcnew SetLableDelegate(this,&Dialog_WaitSomethingIsDone::UpdateTextBox); callBack->Invoke(t); } else { label1->Text=t; } } String^ get() { return label1->Text; } };
Problem:
Wenn eine Invoke gemacht werdne muss, dann wird in UpdateTextBox trotzdem die InvalidOperationException geworfen.
Ist mein Ansatz total falsch?
Geht es irgendwie anders?Ziel ist, das man die Dialog-Klasse einfach einbindet, und die Anzeige variabel ändern kann, ohne das der eigene Thread aufhört zu arbeiten.
Mfg
Reinhold Fischer