Laden...

GUI aus einer anderen Klasse aus einem Thread heraus aktualisieren

12 Antworten
1,728 Aufrufe
Letzter Beitrag: vor 16 Jahren
GUI aus einer anderen Klasse aus einem Thread heraus aktualisieren

Hallo Zusammen,

wie ich durch die Suche erfahren habe, ist dies hier schon ein ziemlich langes und immer wieder kehrendes Thema. Doch beim sichten der vorhanden Topics hab ich mein Problem irgendwie nicht ganz wieder gefunden.

Ich habe ein Form mit einer Statusleiste und einem Backgroundworker. Auf Knopfdruck wird der Backgroundworker gestartet, der eine Methode in einer anderen Klasse aufruft, in der wiederrum eine Methode in einer weiteren Klasse aufruft. In der letzten aufgerufenen Methode wird eine Schleife durchlaufen. Innerhalb der Schleife soll nun die Statusbar im WinForm aktualisiert werden. (Die angehängt Grafik verdeutlicht das hoffentlich noch mal etwas...).

Das man per Invoke die Elemente der GUI aktualisieren kann habe in inzwischen schon gelesen, doch meistens war dann die Verarbeitung noch in der WinForm Klasse, so das man direkt den delegaten bzw. das Control ansprechen konnte.

Wie kann ich nun aus den anderen Klassen heraus die Statusleiste updaten?
Muss ich tatsächlich eine Referenz des WinForms durch alle Klassen durchschleifen oder gibt es da eine elegantere Methode?

Vielen Dank im Voraus.

Beste Grüße

LordK

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

Hallo LordK,

Muss ich tatsächlich eine Referenz des WinForms durch alle Klassen durchschleifen

nein, natürlich nicht und das solltest du auch nicht.

oder gibt es da eine elegantere Methode?

Ja, klar, feuere in der Schleife ein eigenes Event ([FAQ] Eigenen Event definieren), abonniere dieses im GUI und führe im EventHandler die Aktualisierung durch. Dabei Control.Invoke nicht vergessen. Beachte dazu [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke).

herbivore

Wie kann ich nun aus den anderen Klassen heraus die Statusleiste updaten?
Muss ich tatsächlich eine Referenz des WinForms durch alle Klassen durchschleifen oder gibt es da eine elegantere Methode?

schmeiss ein event. das form kann sich dann daran registrieren, bevor du den backgroundworker anschmeisst und dann kannst du in diesem die progressbar aktualisieren.

schmeiss ein event. das form kann sich dann daran registrieren, bevor du den backgroundworker anschmeisst und dann kannst du in diesem die progressbar aktualisieren.

Würde das nicht aber bedeuten, dass die WinForm Klasse schon eine Referenz auf Klasse B haben müsste? Bisher wird eine Instanz der Klasse B ja erst erzeugt, wenn die execute Methode in Klasse A aufgerufen wird.

Danke & Gruß

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

Hallo LordK,

im Zweifel musst du das Event zweistufig werfen, also von B nach A und von A zum GUI.

herbivore

WinForm kann sich den Wert auch mittels einem Timer aus der Klasse B abholen (Property). Wenn WinForm B nicht kennen soll, sondern alles nur über Klasse A laufen soll, definier einfach eine Status-Klasse die den (oder die) aktuellen Werte von B enthält.

Beachten musst du nur, dass der Timer und der Backgroundworker (Thread, ThreadPool, je nach dem) zwei unterschiedliche Threads sind und der Zugriff so via lock erfolgen muss.

Würde das nicht aber bedeuten, dass die WinForm Klasse schon eine Referenz auf Klasse B haben müsste?

Schlimmer würd ichs finden, dass derzeit B dein WinForm kennt. Wenn du später weg von WinForm willst, musst du auch deine Klasse B anfassen. Bei der Verwendung von Events oder einem Gui-Timer hättest du später das Problem nicht.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

du könntest deine methoden auch so erweitern ,das diese einen progressreport-delegate erwarten und diesen dann immer aufrufen, wenn sie etwas zu melden haben. dann kannst du ihnen die methode Progress report vom backgroundworker mitgeben und die gui kann sich direkt an dem backgroundworker event registrieren.

Ich kann zwar im Moment nicht abschätzen, wie elegant / sicher meine Lösung jetzt ist, aber ich hab einfach den Eventhandler in Klasse B einfach als static definiert und das WinForm einfach direkt an dem statischen EventHandler registriert:



KlasseB:

internal static event EventHandler<TextEventArgs> MyEvent;

protected virtual void OnMyEvent(TextEventArgs e)
{
    EventHandler<TextEventArgs> myEvent = MyEvent;
    if (myEvent != null)
    {
        myEvent(this, e);
    }
}

WinForm:

KlasseB.MyEvent += new EventHandler<TextEventArgs>(myObject_MyEvent);

private void myObject_MyEvent(Object objSender, TextEventArgs e)
{
     MessageBox.Show(e.Text);
}


TextEventArgs:

public class TextEventArgs : System.EventArgs
{
    private readonly string text;
    public TextEventArgs(string text): base()
    {
        this.text = text;
    }
    public string Text
    { get { return this.text; } }
}


Ob es gut/schön ist, ist jetzt eine Sache, aber es funktioniert zumindestens. 😁

Gruß

LordK

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.

Ich kann zwar im Moment nicht abschätzen, wie elegant / sicher meine Lösung jetzt ist

aber ich... das ist echt mist.

Ob es gut/schön ist, ist jetzt eine Sache, aber es funktioniert zumindestens.

das ist der untergang der allermeisten programme. mach es sauber oder mach es garnicht ist da meine weisheit.

die möglichkeiten sind im thread bereits genannt.

Absoluter Mist ist es deshalb, weil du ab jetzt nicht mehr flexibel bist und keine Möglichkeit mehr zum skalieren hast. Du bist auf immer und ewig daran gebunden, das nur ein WinForm und ein Worker gleichzeitig existieren können.

Weiterhin tragen statische Member absolut nicht zur Übersichtlichkeit bei.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Hallo LordK,

mal abgesehen davon, dass das Control.Invoke fehlt. 😃

herbivore

mal abgesehen davon, dass das Control.Invoke fehlt. 😃

Das kam später noch 😉
Das war nur der erste Test ob es überhaupt funktioniert.

Aber ich denke mal ich werde jetzt die Variante von herbivore probieren. Die mit der Statusklasse gefällt mir nicht so ganz und die mit dem progressreport-delegate kann ich mir im Moment nicht vorstellen, wie das aussehen müsste.

Danke für eure Hilfe

Gruß

LordK

Programmieren in C# hält die grauen Zellen am Leben.
Es schärft alle fünf Sinne: den Schwachsinn, den Blödsinn, den Wahnsinn, den Unsinn und den Stumpfsinn.