Invoke aus anderer Klasse als die Form-Klasse [geht doch].

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Invoke aus anderer Klasse als die Form-Klasse [geht doch].

    Hallo Gemeinde,

    in einer älteren WinForm-Anwendung, in C# geschrieben, wird leider noch sehr viel mit dem Hauptform, also dem MainWindow gemacht. Externe Klassen sind wenig verwendet worden.
    Um Async auf ein ToolStripStatusLabel zugreifen zu können, der Text soll geändert werden können, verwende ich folgenden Code:
    frmMain

    C#-Quellcode

    1. internal delegate void SetStatusTextDelegate(string value, bool wait);
    2. internal SetStatusTextDelegate SetStatusText;
    3. private void SetStatusTextMethod(string value, bool wait)
    4. {
    5. if (wait)
    6. Cursor.Current = Cursors.WaitCursor;
    7. else
    8. Cursor.Current = Cursors.Default;
    9. tsStatusLabel.InvokeIfRequiredToolstrip(o =>
    10. {
    11. o.Text = value;
    12. });
    13. }


    In der selben Klasse wird über ein Ereignis eine Funktion als Task, als Nebenläufig, aufgerufen und hier wird der Label wie folgt angepasst:

    C#-Quellcode

    1. Invoke(new SetStatusTextDelegate(SetStatusText), "Irgend etwas passiert hier gerade ...", true);


    Nun möchte ich bestimmte Vorgänge in seperate Klassen unterbringen, also nicht in der public partial class frmMain-Klasse. Die Fehlermeldungen sind banal, die Lösung ist aber nicht offensichtlich.
    Zunächst habe ich die Zeile geändert in:

    C#-Quellcode

    1. frmMain.Invoke(new frmMain.SetStatusTextDelegate(frmMain.SetStatusText), "Irgend etwas passiert hier gerade ..", true);

    Ein Fehler im Abschnitt frmKonverter.SetStatusText ist offensichtlich: CS0120: Für das nicht statische Feld, die Methode oder die Eigenschaft "frmMain.SetStatusText" ist ein Objektverweis erforderlich.
    Verstanden, aber ich dachte mir, dann mach das Feld doch statisch und gut:

    C#-Quellcode

    1. internal static SetStatusTextDelegate SetStatusText;

    So jetzt ist aber der Fehler ganz nach vorne gerückt und lautet: CS0120: CS0120: Für das nicht statische Feld, die Methode oder die Eigenschaft "Control.Invoke(Delegate, params object[])" ist ein Objektverweis erforderlich.

    Hier bin ich raus, ich schnalle die Syntax einfach nicht, bei einer Form wäre es

    C#-Quellcode

    1. frmSettings frm = new frmSettings();

    aber hier weiß ich nicht weiter.

    Kann mir jemand freundlicherweise erklären, was ich machen muss um das Invoke zum Laufen zu bringen?
    Merci :)
    Ich bin in C# nicht drin, aber frmMain ist schon als Objektinstanz vorliegend, oder?
    Weiterführende Infos auf stackoverflow (?)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Objektinstanz vorliegend, oder?
    Ja.
    So nen VB6-Hackmack gibt es in C# nicht.
    @Dksksm Du kannst invoken ohne oder mit Rückgabe eines Resultats ohne Delegate.
    Nutze Task bzw. Func.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    VaporiZed schrieb:

    frmMain ist schon als Objektinstanz vorliegend, oder?

    na, die Fehlermeldung CS0120 sagt doch, dass dem nicht so ist.
    Dksksm versucht einen Datentypen zu invoken und wundert sich.
    Letztlich über den Unterschied zwischen Datentyp und Objekt/ObjektInstanz.

    Das wird ja in Vb blöderweise total verwischt, sodass es dann auch schwer ist zu begreifen.
    Ich verstehe die Antworten nicht oder kann sie nicht umsetzen.
    Ich habe jetzt eine Beispielanwendung ohne ausführbaren Code mit @ErfinderDesRades seinem SolutionExplorer erstellt und hänge das an.
    Vielleicht seht ihr ja meinen Fehler, ich verstehe leider nur Bahnhof bei @VaporiZed's weiterführendem Link.
    Solche Seiten habe ich natürlich längst selbst ergooglelt, und versucht zu verstehen. Ich verstehe das einfach nicht mehr, das ist mir zu hoch, zu abstrakt trotz der Beispiele.
    Sorry aber ich bin nur ein alter Typ, ein Autodidakt, habe jetzt noch 2 Jahre, dann bin ich Rentner (nicht vorzeitig), habe nichts als eine kaufmännische Ausbildung und das ist auch schon gefühlte 100 Jahre her.

    Vielleicht erbarmt sich ja einer.....

    InvokeUnverstaendnis00.zip
    ich gucks mir grad an, aber kann ich nicht fixen, weil ergibt iwie keinen Sinn.
    Was soll denn das Programm tun?

    Es gibt in dem Programm überhaupt keinen langdauernden Vorgang, bei dem es Sinn ergäbe, ihn in den NebenThread zu verlegen.

    Im NebenThread nix anneres zu tun als mit Invoke eine Anweisung in den Haupt-Thread zurück-zutransferieren - da lass den NebenThread doch gleich weg, haste gewaltig Resourcen gespart.
    Nein das *Beispiel* enthält ausschliesslich den Code den es benötigt zu demonstrieren, dass ich es **nicht** hinbekomme aus einer anderen Klasse heraus das ToolStripStatusLabel zu invoken.
    ich kann kein Projekt mit zig-tausend Zeilen als Demo meines Versagens hier hochladen, dafür reicht der Code doch aus.
    Es geht ausschliesslich darum, dass ich liebend gerne anstatt eben die Form-Klasse noch weiter aufzublähen (da habe ich allein schon public partial class FormMain), dafür *je* eine eigene Klasse hätte.

    Aus dem asyncen Nebenthread heraus kann ich ja invoken, das ist nicht mein Problem, nur habe ich bereits 6 MB Code allein in dieser Form über alle Dateien (partial class).
    na schön.
    Habich was hingebastelt, aber glaub kaum, dasses zum Verständnis beiträgt.
    Aber immerhin erfüllts deinen einzigen Wunsch.

    C#-Quellcode

    1. using static InvokeUnverstaendnis.Form1;
    2. using System.Windows.Forms;
    3. namespace InvokeUnverstaendnis {
    4. internal class InvokeTest {
    5. internal static bool StartTest() {
    6. //Form1 form1 = new Form1(); // eine neue Instanz ist ja nicht was ich will und auch nicht darf!
    7. //Form1.BeginInvoke(new SetStatusTextDelegate(SetStatusText), "Compiliert nicht, weil kein Objektverweis.", false);
    8. Form form1 = Application.OpenForms[0];
    9. form1.BeginInvoke(new SetStatusTextDelegate(SetStatusText), "Crasht nicht.", false); //Ein neues Fensterhandle soll ja auch gar nicht erstellt werden
    10. return true;
    11. }
    12. }
    13. }
    Wow, man kann also erzwingen, dass die Instanz auf eine bereits geöffnete From erzeugt wird, ist das sprachlich so korrekt?
    Das wusste ich nicht, aber ist so simpel wie genial.
    Bei mir muss es übrigens Form1 form1 = (Form1)Application.OpenForms[0]; heißen, damit es compiliert. Das nennt man wohl Directcast, nehm ich an.
    Super Sache ist das. Natürlich ist das "nur" ein erster Schritt zu versuchen, die Applikation in kleiner Einheiten (Klassen) zu zerstückeln.
    Aber erst dann kann ich diese immer noch großen Broken in kleinere Funktionen abspecken. Es wird Stück für Stück übersichtlicher, danke dir.

    Dksksm schrieb:

    Bei mir muss es übrigens Form1 form1 = (Form1)Application.OpenForms[0]; heißen, damit es compiliert.

    nein - es darf ruhig so heissen wie ich schrieb:

    C#-Quellcode

    1. Form form1 = Application.OpenForms[0];
    Beachte, dass Form ein anderer Datentyp ist als Form1. ich schrieb Form - die Basisklasse von Form1.

    Dksksm schrieb:

    Wow, man kann also erzwingen, dass die Instanz auf eine bereits geöffnete From erzeugt wird, ist das sprachlich so korrekt?
    Leider nein. Sondern ergibt keinen Sinn der Satz.
    Eine Instanz auf eine bereits geöffnete Form erzeugen? Was soll damit gemeint sein?
    Eine Instanz erzeugt man von einem Datentyp. Man verwendet dafür das Schlüsselwort new. Im Code kommt dieses Schlüsselwort nicht vor, also wird da auch ganz bestimmt keine Instanz von irgendetwas erzeugt.
    Form form1 = Application.OpenForms[0]; Ich weise nur einen Wert einer Variablen zu. Eine Zuweisung ist das.
    Ich schrieb "Compiliert nicht"! Ich kann es nicht ändern, es tut nicht wie du sagst.
    Ich kann statt Form1 allerdings, was ich eh gewollt hätte aber nicht geschrieben hatte, Form verwenden. Trotzdem *will* der Compiler:
    Form form1 = (Form)Application.OpenForms[0];

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Dksksm“ ()

    Dksksm schrieb:

    Trotzdem *will* der Compiler: Form form1 = (Form)Application.OpenForms[0];
    … was korrekt ist und ja auch dem entspricht, was @ErfinderDesRades geschrieben hat :whistling:
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen


    Auch wenn ich nicht der Programmierer unter dem Herrn bin, ein Lügner bin ich jedenfalls nicht.
    Und es wäre nett, wenn hier jetzt geschlossen werden könnte.
    Ich weiß schon warum ich hier nicht gerne schreibe, ich fühle mich hier permanent nicht ernst genommen und als Depp hingestellt.
    Ja ihr seid die Helden. Tschüß
    @Dksksm Du hast offensichtlich zwei verschiedene Dingense, die sich auf Form beziehen.
    Nimm mal diese Zeile raus:

    C#-Quellcode

    1. using static InvokeUnverfstaendnis.Form;
    oder mach da

    C#-Quellcode

    1. using static InvokeUnverfstaendnis.Form1;
    draus.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ja ging nicht, weil die Form1 gar nicht mehr Form1 hieß (Im Projektmappen-Explorer schon, aber im Code nicht), sondern Form. Das darf natürlich nicht sein, keine Ahnung wann und wo das im Beispiel passiert ist. Nach dem Umbenennen der Form in Form1 im Code und in der Designer.cs ging es so, wie ihr das geschrieben habt.

    Dksksm schrieb:

    ich fühle mich hier permanent nicht ernst genommen und als Depp hingestellt.
    Das ist nicht meine Absicht, und bitte fühl nicht so.

    Ich hab einfach nur ebenso hartnäckig behauptet, was richtig ist, wie du, was falsch ist.
    Und der "Leidensweg" hat sich doch gelohnt: Am Ende hat sich herausgestellt, woran es lag, dasses sich bei dir so eigentümlich verhalten hat.
    Ich finde das einen wichtigen und wertvollen Erkenntnisgewinn, zu verstehen, dass Application.OpenForms[0] vom Typ Form ist, und dass man ein Form nicht auf Form casten muss - weil es das ja schon ist.
    Und einen Einblick in die Problematik von Namenskonflikten hast du gewonnen - dassis eiglich nochmal soviel wert.