PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C#: Dialog in eigenem Thread laufen lassen


Elemental
2003-12-18, 13:28:58
Ich versuche gerade, einen kleinen Dialog mit einem ProgressBar in einem eigenen thread laufen zu laufen:


//display the ProgressDialog
ProgressDialog progressDialog = null;
System.Threading.Thread progressDialogThread = null;
if( bShowProgressDialog == true )
{
progressDialog = new ProgressDialog( selectedIdentities.Count, m_ResourceManager);

progressDialogThread = new System.Threading.Thread( new System.Threading.ThreadStart( progressDialog.Show ) );

progressDialogThread.Priority = System.Threading.ThreadPriority.AboveNormal;

progressDialogThread.Start();

//create an eventhandler to see if the user closes the dialog

progressDialog.Closed += new System.EventHandler(this.ProgressDialog_Closed);
}




Allerdings blitzt der Dialog nur kurz auf und is dann gleich wieder weg. Was mach ich denn verkehrt?


mfG
Elemental

Demirug
2003-12-18, 13:45:26
Grausam. Sorry.

1. Man sollte sich es immer mindestens 10 mal überlegen ob man einen zweiten UI-Thread in einer Anwendung braucht.

2. Wenn es dann dann wirklich sein muss:

Die Threadfunktion für diesen neuen Thread muss den Dialog erzeugen und dann mit Application.Run starten. Braucht man den Dialog und den Thread nicht mehr muss man innerhalb dieses Threads Application.ExitThread aufrufen.

Gast
2003-12-18, 13:53:11
Original geschrieben von Demirug
Grausam. Sorry.


Nix gegen meinen eleganten Programmierstil ;D

Elemental
2003-12-18, 13:53:44
war ich gerade...

Demirug
2003-12-18, 14:00:07
Original geschrieben von Gast
Nix gegen meinen eleganten Programmierstil ;D

Das bezog sich nicht auf den Stil sondern auf die Idee mit dem Dialog in einem eigenen Thread.

Elemental
2003-12-18, 14:25:46
Dann bin ich ja beruhigt. :)

Elemental
2003-12-18, 17:29:23
Gibts auch ne Möglichkeit, wie ich diesen Dialog der im extra Thread läuft dann wieder aprupt beenden kann?
Mit
progressDialogThread.Abort();

bleibt der Dialog immernoch für ein paar Sekunden da.


Gruss
Elemental

KiBa
2003-12-18, 19:14:03
mal so als kleine anmerkung... die windows forms sind eine der wenigen libraries im framework, welche nicht thread-safe sind, da sie direkt auf win32 aufsetzen. d.h. wenn du versuchst, daten von deinem dialog vom hauptthread aus zu lesen oder zu schreiben, kracht's (oder mit pech auch nicht, sondern stunden später an anderer stelle)
da muss man mit invoke() und konsorten arbeiten, um sowas zu verhindern, was aber nicht so schön ist. am besten man vermeidet bei benutzung der forms die benutzung von threads...
siehe auch hier: http://msdn.microsoft.com/library/en-us/cpguide/html/cpcondevelopingmultithreadedwindowsformscontrol.asp

grakaman
2003-12-18, 19:50:23
Original geschrieben von Elemental
Gibts auch ne Möglichkeit, wie ich diesen Dialog der im extra Thread läuft dann wieder aprupt beenden kann?
Mit
progressDialogThread.Abort();

bleibt der Dialog immernoch für ein paar Sekunden da.


Gruss
Elemental

Es ist nicht fein, dass du mit dem Beenden des Threads die darin befindlichen Objekte "zwingen" willst, sofort ihre Aufgaben zu beenden. Zumindest hier konfrontierst du mit dem GC. Aber, die ProgressBar besitzt eine Dispose Methode. Implementiere bitte in deiner ProgressDialog Klasse eine Dispose Methode und rufe die ProgressBar dann in einer "using" Anweisung auf. Dann rufst du in deiner implementierten Dispose Methode die Dispose Methode der ProgressBar auf. Btw, was genau macht denn so deine ProgressDialog Methode?

MfG

Elemental
2003-12-19, 11:13:28
ProgressDialog ist ein kleines Dialog Fenster, in welchem ein ProgressBar den Status anzeigt, während im Hintergrund eine Datenbank durchsucht wird.


Hab das Problem jetzt einfach so gelöst, dass ich erst
ProgressDialog.Hide()
rufe, bevor ich mit
progressDialogThread.Abort();
versuche den Thread zu beenden.


Nur die implementierung eines Cancel-Buttons im ProgressDialog form macht mir noch Probleme. Stichwort ThreadAbortException :D

grakaman
2003-12-19, 12:21:23
Und warum kannst du nicht die Form direkt beenden?

Elemental
2003-12-19, 12:40:18
Naja, wenn ich den Thread beende wird der Dialog doch automatisch auch beendet, oder?

Ich werd mal das Hide() durch Dispose() ersetzen und schauen obs läuft.

grakaman
2003-12-19, 12:49:44
Original geschrieben von Elemental
Naja, wenn ich den Thread beende wird der Dialog doch automatisch auch beendet, oder?

Ich werd mal das Hide() durch Dispose() ersetzen und schauen obs läuft.

Die Form selbst kannst du doch mit Close schließen. Am besten du erstellst eine eigene Methode, in der du die ProgressDialog instanzierst und mit Show zeigst. Wenn du fertig bist, einfach mit Close beenden. Und diese Methode nimmst du dann als ThreadStart.

Elemental
2003-12-19, 13:02:14
Wie meinst du das jetzt mit dem Close. Wo soll ich close rufen?

Habs jetzt mal so:


/// <summary>
/// Creates a modal dialog that runs in a seperate thread
/// </summary>
private void CreateProgressDialog()
{
m_ProgressDialog.ShowDialog();
}


private void AndereMethode()
{
//display the ProgressDialog
if( bShowProgressDialog == true )
{
m_ProgressDialog = new ProgressDialog( selectedIdentities.Count, m_ResourceManager);

m_ProgressDialogThread = new System.Threading.Thread( new System.Threading.ThreadStart( CreateProgressDialog ) );

m_ProgressDialogThread.Priority = System.Threading.ThreadPriority.AboveNormal;

m_ProgressDialogThread.Start();

//create an eventhandler to see if the user closes the dialog
m_ProgressDialog.Closed += new System.EventHandler(this.ProgressDialog_Closed);
}

foreach(Identity identity in selectedIdentities)
{
//check if the user already canceled the action
if( m_bProgressCanceled == true )
{
break;
}

//do some stuff here

//increase the ProgressBar
if( bShowProgressDialog == true )
{
m_ProgressDialog.IncreaseProgressBar();
}
}

//close the ProgressDialog
m_ProgressDialog.Dispose();
m_ProgressDialogThread.Abort();
}

/// <summary>
/// Close the ProgressDialog since the user clicked cancel
/// </summary>
private void ProgressDialog_Closed(object sender, System.EventArgs e)
{
try
{
m_bProgressCanceled = true;

//now close the ProgressDialog, but don't abort the thread since this causes a ThreadAbortException
m_ProgressDialog.Dispose();
}
catch(Exception ex)
{
Services.NotificationService.PublishErrorMsg(this, ex.Message);
}
}

grakaman
2003-12-19, 13:17:49
Na wie löst du denn das Ereignis Closed aus? Doch nicht durch das Beenden des Threads? Du hast doch sicher in der ProgressDialog Form einen Button, der die Form schließen soll oder? Dann schreib doch in den Click EventHandler einfach ein this.Close() Oder versteh ich jetzt irgend etwas nicht richtig?

MfG

Elemental
2003-12-19, 13:27:56
Ich hab nen Eventhandler und mache da auch this.close(), aber der Dialog verschwindet nicht sofort.
Deswegen kam ich ja auf die Idee mit dem Hide().

Elemental
2003-12-19, 13:45:29
Oh jetzt check ich meinen Fehler. Close() wird nur in meinem eventhandler des Cancel-Buttons gerufen, aber nicht im Hauptprogramm, bevor ich den Thread beende.
So ein blöder Fehler... :eyes:

grakaman
2003-12-19, 13:56:44
So geht das:

Form1:


private void button1_Click(object sender, System.EventArgs e)
{
this.progressThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.NewThread));
this.progressThread.Start();
}

private void NewThread()
{
Application.Run(new ProgressDialog());
}



Und hier deine ProgressDialog Form:

...

private void button1_Click(object sender, System.EventArgs e)
{
this.Close();
}

Elemental
2003-12-19, 14:33:18
Application.Run(new ProgressDialog)

kann ich aber nicht verwenden, da ich dann von meinem "Hauptprogramm" nicht mehr auf die Instanz von ProgressDialog zugreifen kann.

Drum hab ich ein Membervariable m_ProgressDialog und verwende m_ProgressDialog.ShowDialog.

Naja, jedenfalls funktionierts jetzt. Danke nochmals für die Unterstützung :)

Gruss
Elemental

grakaman
2003-12-19, 14:51:31
Original geschrieben von Elemental
Application.Run(new ProgressDialog)

kann ich aber nicht verwenden, da ich dann von meinem "Hauptprogramm" nicht mehr auf die Instanz von ProgressDialog zugreifen kann.

Drum hab ich ein Membervariable m_ProgressDialog und verwende m_ProgressDialog.ShowDialog.

Naja, jedenfalls funktionierts jetzt. Danke nochmals für die Unterstützung :)

Gruss
Elemental

Natürlich geht das:


this.progressThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.NewThread));
this.progressThread.Start();
Thread.Sleep(1000);
this.progressDialog.ShowBox();


Beispielmethode in der ProgressDialog


public void ShowBox()
{
MessageBox.Show("Hallo Welt");
}

Elemental
2003-12-19, 14:56:56
Aper es gibt doch überhaupt keine Instanz mit dem Namen "progressDialog", da der Dialog ja blos über 'Application.Run(new ProgressDialog)' erzeugt wird.

???

grakaman
2003-12-19, 15:04:42
Original geschrieben von Elemental
Aper es gibt doch überhaupt keine Instanz mit dem Namen "progressDialog", da der Dialog ja blos über 'Application.Run(new ProgressDialog)' erzeugt wird.

???

Stimmt, habe ich vergessen zu erwähnen. Dann machst du eben ein Feld daraus und erzeugst erst die Instanz in Application.Run, also

public ProgressDialog myProgress;
...

Application.Run(myProgress = new ProgressDialog());

MfG

Elemental
2003-12-19, 15:22:50
OK, aber wieso spielt es eine Rolle, ob ich Application.Run() oder ShowDialog() verwende.

Is doch eigentlich egal, oder?

grakaman
2003-12-19, 15:35:47
Original geschrieben von Elemental
OK, aber wieso spielt es eine Rolle, ob ich Application.Run() oder ShowDialog() verwende.

Is doch eigentlich egal, oder?

Naja, Application.Run gibt erst die Steuerung zurück, wenn die Instanz gelöscht wird. ShowDialog ist zwar modal, aber trotzdem kann ja nach dem Aufruf imo weiter abgearbeitet werden.

MfG

edit: ShowDialog und Application.Run scheinen doch auf dem ersten Blick das selbe Resultat zu erzielen. ShowDialog gibt auch erst die Steuerung zurück, wenn es geschlossen wird. Aber es blockiert auch den Nachrichtenempfang der Parent Form, dafür kann es im selben Thread laufen. Bei Application.Run brauchst du dann eben einen separaten Thread, dafür läuft die Parent Form aber auch unabhängig weiter. Das selbe Ergebnis hat man aber auch, wenn man ShowDialog in einem separaten Thread für die Form aufruft. Nunja, bei Application.Run muss man zumindest weniger Code schreiben :D

Elemental
2003-12-20, 18:49:04
Das heisst mit Application.Run() hätte ich mir den ganzen Aufwand mit Thread erzeugen sparen können, weil das alles automatisch gemacht wird? :chainsaw:

grakaman
2003-12-20, 19:26:33
Original geschrieben von Elemental
Das heisst mit Application.Run() hätte ich mir den ganzen Aufwand mit Thread erzeugen sparen können, weil das alles automatisch gemacht wird? :chainsaw:

Nein, nein. Du kannst nicht zwei Application.Run in einem Thread haben. Mit weniger schreiben meinte ich eigentlich die überflüssige Zeile, wo du die ShowDialog aufrufst.
Allerdings ist es ja dann auch nicht modal.