Klasse als Ergebnis einer nicht modalen Form zurückgeben

  • VB.NET
  • .NET 4.5

Es gibt 24 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    Klasse als Ergebnis einer nicht modalen Form zurückgeben

    Wie kann ich bei einem selbstgestalteten nicht modalen Fenster welches nach einem Buton Event angezeigt wird, eine Klasse als Rückgabe an mein Hauptprogramm übergeben?

    Modal, also über frm.ShowDialog ist das alles ganz einfach. Nur mit frm.Show sieht es ganz anders aus und auch bei Google bin ich bisher noch über keine Lösung gestolpert.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:
    Abboniere das FormClosing-Event und reagiere dort drin. So z.B.:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Frm As New MyForm
    3. Private Sub Frm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs)
    4. MessageBox.Show(Frm.SC.var.ToString())
    5. End Sub
    6. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    7. Frm.SC.var = 10
    8. AddHandler Frm.FormClosing, AddressOf Frm_FormClosing
    9. Frm.Show()
    10. End Sub
    11. End Class
    12. Public Class MyForm
    13. Inherits Form
    14. Public SC As New SomeClass
    15. End Class
    16. Public Class SomeClass
    17. Public var As Integer
    18. End Class
    Ich würd's per EventRaising machen:

    VB.NET-Quellcode

    1. Public Class FrmMain
    2. Private DialogForm As New Frm
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. DialogForm.Show(Me)
    5. End Sub
    6. Private Sub Receive_ClassObject(sender As Object, e As ObjectClass)
    7. e.ShowMyInt()
    8. End Sub
    9. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    10. AddHandler DialogForm.Report_ClassObject, AddressOf Receive_ClassObject
    11. End Sub
    12. Private Sub FrmMain_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    13. DialogForm.Dispose()
    14. End Sub
    15. End Class
    16. Public Class Frm : Inherits Form
    17. Public Event Report_ClassObject As EventHandler(Of ObjectClass)
    18. Private Sub Frm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    19. Dim ObjectInstance As New ObjectClass
    20. RaiseEvent Report_ClassObject(Me, ObjectInstance)
    21. End Sub
    22. End Class
    23. Public Class ObjectClass
    24. Private IntVariable As Integer = 42
    25. Public Sub ShowMyInt()
    26. MessageBox.Show(IntVariable.ToString)
    27. End Sub
    28. End Class

    ...was bei genauerer Betrachtung effektiv das Gleiche ist :S
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Events sind Ereignisse welche ausgelöst werden, wird das Event ausgelöst wird die Sub aufgerufen, welche diesem Event "zugeordnet" wurde, kennst du bestimmt schon vom Button.Click. Du kannst auch Events von anderen Objecten abbonieren, dazu brauchst du eine Sub welche die passenden Argumente nimmt.

    VB.NET-Quellcode

    1. Private Sub Frm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs)
    2. End Sub


    Das hast du so ähnlich sicher schon beim Form_Load gesehen, nur das hinterdran Handles FormXYZ.FormLoad steht da siehst du welches Event vom welchem Object abboniert wurde, im Beispiel habe ich das nicht, weil ich das Event selbst abboniert habe.

    VB.NET-Quellcode

    1. AddHandler Frm.FormClosing, AddressOf Frm_FormClosing


    Mit dem Handles... hinten dran klappt nur wenn das Object als WithEvents deklariert ist.

    Schau auch mal wenn du im Designer bist im Eigenschaftenfenster, klicke dort mal auf dem Blitz, dann siehst du vom selektierten Control welche Events zur verfügung stehen, kannst sie auch dort abbonieren.
    Handles Me.FormClosing

    Me ist doch die Form selbst, nicht aber Frm

    Wenn du das so machen möchtest dann erstmal so als "WithEvents" deklarieren, dann klappt das so:

    VB.NET-Quellcode

    1. Private WithEvents Frm As New MyForm
    2. Private Sub Frm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Frm.FormClosing
    3. End Sub
    Das in die Klasse der Form, auf welcher der Button ist.

    VB.NET-Quellcode

    1. Private WithEvents Frm As New MyForm
    2. Private Sub Frm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Frm.FormClosing
    3. End Sub


    Da jetzt die Klasse deines 2. Form wohl nicht MyForm ist, schaust mal nach wie die Klasse des 2. Form heist und nimmst anstatt MyForm den Klassennamen des 2. Forms. Wenn du sie nicht umbenannt hast z.B. Form2, Form3 etc...
    Das funktioniert so nicht. Das liegt zwar nicht daran, dass Du den Microsoft.VisualBasic-Namespace drinnen hast, aber der sollte trotzdem raus.
    Dein Code

    VB.NET-Quellcode

    1. Dim hiersollendatenrein As Class1 = New Class1
    2. hiersollendatenrein.text = ""
    3. Dim frm As Form2 = New Form2
    4. frm.Show() ' kein ShowDialog verwenden
    5. If hiersollendatenrein.text = "huhu" Then
    6. MsgBox("hat geklappt")
    7. Else
    8. MsgBox("hat nicht geklappt")
    9. End If
    zeigt ein Formular (frm vom Typ Form2) an und wertet danach, gleich nachdem dem Form per Show befehligt wird, sich zu zeigen, die Class1-Klasseninstanz (hiersollendatenrein) auf. Da ist noch nix Relevantes in frm passiert. Klar, man könnte in den Form2_Shown-EventHandler reinschreiben. Aber irgendwie hab ich das Gefühl, dass das etwas einschränkend wäre. Da soll doch bestimmt noch was auf frm/Form2 passieren, oder? Irgendwelche Eingaben z.B.

    Ich bin davon ausgegangen, dass sich Deine zu manipulierende Klasseninstanz in frm befindet und Form1 die erhalten soll. Dann arbeitet man mit Events. Wenn allerdings das Unterformular eine Variable des Hauptformulars ändern soll, dann übergib vom Hauptformular die Variable an das Unterformular und fertig.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim hiersollendatenrein As Class1 = New Class1
    4. hiersollendatenrein.text = ""
    5. Dim frm As Form2 = New Form2
    6. frm.ManipulateClass1Instance(hiersollendatenrein)
    7. frm.Show() ' kein ShowDialog verwenden
    8. If hiersollendatenrein.text = "huhu" Then
    9. MsgBox("hat geklappt")
    10. Else
    11. MsgBox("hat nicht geklappt")
    12. End If
    13. End Sub
    14. End Class
    15. Public Class Form2
    16. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    17. Me.Dispose()
    18. End Sub
    19. Public Sub ManipulateClass1Instance(Instance As Class1)
    20. Instance.text = "huhu"
    21. End Sub
    22. End Class


    Stellt sich nur die Frage, wie bald die Variable geändert wird. Wenn man wirklich auf frm-Eingaben des Benutzers warten muss, dann geht es m.E. auch nur mit Events. Stell Dir das mit Events folgendermaßen vor.
    Ein Objekt raised ein Event (per RaiseEvent) - verflucht, warum find ich auf Anhieb keine schöne Übersetzung dafür? Egal. Es geht ja um folgendes: Ein Button raised das Event Click. Das ist so, als ob der Button ne Nachricht an schwarze Brett pinnt: "Ich wurde angeklickt." Das schwarze Brett wird vielleicht ggf. von anderen Objekten angeschaut. Das sind sogenannte EventHandler. Und vielleicht ist auch ein EventHandler (oder auch mehrere) dabei, dass sich für jene Nachricht interessiert. Wenn es jene Nachricht am schwarzen Brett gibt, bekommt der EventHandler das mit und wird selbst aktiv.

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. End Sub

    Hast Du schon oft gesehen und verwendest es ja selber. Dies ist ein EventHandler namens Button1_Click. Der kann auch RäuberHotzenplotz heißen, das ist wurscht. Relevant ist, dass er sich für das Button1.Click-Event interessiert. Zu erkennen an Handles Button1.Click. Immer, wenn Button1 nen Click meldet, also ans hypothetische schwarze Brett pinnt, wird jener EventHandler, also jene Prozedur aufgerufen und ausgeführt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Ich täte dem Konzept nochmal nach-leuchten - es ist imo nämlich noch ühaupt nicht definiert, was eiglich passieren soll.
    Also in dieser Problemstellung sind 2 Unsinne drin, und müssen geklärt werden:

    oobdoo schrieb:

    Wie kann ich bei einem selbstgestalteten nicht modalen Fenster welches nach einem Buton Event angezeigt wird, eine Klasse als Rückgabe an mein Hauptprogramm übergeben?
    1. VB hat (normalerweise) kein "Hauptprogramm".
      Es gibt ein MainForm, und wenn das geschlossen wird, ist das Programm beendet.
      Ist mit "Hauptprogramm" dieses MainForm gemeint?
    2. ein nicht-modales Fenster hat keine Rückgabe.
      Nur bei einem modalen Fenster kann man von Rückgabe sprechen, nämlich die Rückgabe der Form.ShowDialog() - Methode. Aber genau die ist bei nicht-modal ja nicht gegeben, also was ist gemeint mit "Rückgabe"?
      Soll das Form danach geschlossen werden (wie bei einem modalen Form) oder weiter anzeigen?
      Und soll das MainForm - wenn das mit "Hauptprogramm" gemeint ist - gesperrt sein, bis die Eingabe ins Form vollzogen ist? (das ist ja meist sehr sinnvoll)
    Aus Klärung dieser Fragen ergibt sich imo eindeutig, ob und welche der beiden bislang angedeuteten Wege gangbar ist.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    VB hat (normalerweise) kein "Hauptprogramm".
    Es gibt ein MainForm, und wenn das geschlossen wird, ist das Programm beendet.
    Ist mit "Hauptprogramm" dieses MainForm gemeint?

    Sorry manchmal bekomme ich die Begriffe etwas durcheinander. Aber Du hast natürlich recht. "Mein Hauptprogramm" ist natürlich die MainForm.


    ErfinderDesRades schrieb:

    ein nicht-modales Fenster hat keine Rückgabe.

    Da mag ja so sein. Ich persönlich finde es aber immer furchtbar, wenn durch ein weiteres Fenster die MainForm blockiert wird. Ich habe es schon oft genug gehabt, das ich für irgendwelche Eingaben in einem Programm irgend etwas benötigte was auf dem Desktop lag.
    Daher wollte ich genau das in meinem Programm vermeiden. Mit ShowDialog bekomme ich so etwas auch hin.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:
    Wie es ausschaut scheint mittlerweile ein bischen was zu funktionieren. Das war mir erst heute morgen aufgefallen, als ich zufällig das Fenster über das kleine Kreuz rechts oben geschlossen hatte.

    In meinem Projekt habe ich aber drei Button im neu geöffneten Fenster. Jeder davon schließt das Fenster mit Me.Dispose. Durch rumprobieren hatte ich das Dispose durch Close ersetzt und nun scheinen auch die Events mit der Rückgabe zu funktionieren.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:

    ErfinderDesRades schrieb:

    • was ist gemeint mit "Rückgabe"?
    • Soll das Form danach geschlossen werden oder weiter anzeigen?


    So ähnlich schaut es bei mir aus.

    VB.NET-Quellcode

    1. Public Class meineklasse
    2. Public text As String
    3. End Class
    4. Public Sub MainForm()
    5. Dim mk As meineklasse = New meineklasse
    6. Dim mf As meinfenster = New meinfenster(mk)
    7. mf.Show()
    8. End MainForm


    Das Formular meinfenster soll danach geschlossen werden und erst bei Bedarf wieder neu entstehen.
    Mit Rückgabe ist gemeint, das Formular meinfenster entsprecher einer Useraktion die Klasse meineklasse beschreibt, damit ich mit der in der MainForm weiter arbeiten kann.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:

    oobdoo schrieb:

    So ähnlich schaut es bei mir aus.
    Und wie sieht es konkret bei Dir aus? Denn der gezeigte Code ergibt m.E. überhaupt keinen Sinn.
    Wenn jetzt 2 Fenster gleichzeitig offen sind (MainForm und ChildForm), was soll denn passieren, wenn jemand in MainForm an meineklasse rumspielt, dann wechselt zu ChildForm und da auch rumspielt? Welche Werte sind dann die richtigen? Das ist dann m.E. das gleiche Dilemma wie bei ner Datenbank mit mehreren Benutzern oder Multithreadingbearbeitung an den selben Daten. Da stellt sich dann auch die Frage: Wer hat recht? Bzw: Wessen Daten werden akzeptiert? Daher ist das ganze Konstrukt, welches Du anstrebst, noch fragwürdig.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    hmm - ich finde den Code sinnvoll, und er wird auch wohl machen, was er machen soll: Das MainForm erzeugt ein meineKlasse-Objekt und übergibt das ans ChildForm.
    Das Childform setzt irgendwelche Werte in dem Objekt.
    Wird das ChildForm geschlossen, soll das MainForm das meineKlasse-Objekt auswerten.

    Eiglich ist alles paletti - das MainForm muss das Form_Closed-Event des ChildForms abonnieren, und kann da die meineKlasse-Werte auswerten.

    Was ist problem?
    Ja, ok, meine Aussage ist möglicherweise etwas übertrieben gewesen. Wenn alles so läuft, ist ja gut.
    Mir geht es darum, dass wir den "echten" Code nicht sehen. Am Ende scheitert es dann an solchen Sachen, wie wir hier schon häufiger im Forum hatten: "Es will nicht, ich habe alles genauso gemacht, wie Ihr gesagt habe. Ok, ich habe nicht meinen Originalcode gepostet. Dann eben hier der Originalcode. Ach, das hätte ich auch beachten sollen? Warum sagt mir das denn keiner? Dass es an sowas Kleinem scheitern kann. Hätte ich nicht gedacht." Dass Argumente an den Konstruktor übergeben werden, ist für mich auch so ne Sache. Ich selber mach es ungern, sondern benutz dafür ne extra Übergabe-Sub. Der Grund: Exception-swallowing. V.a. wenn die übergebende Klasseninstanz komplex ist und auch noch anfänglich vom ChildForm ausgewertet werden soll, tritt ggf. irgendwo Fehlverhalten auf und keiner weiß, warum. Da es beim TE noch Verständnisprobleme bei der Funktionsweise und Anwendung von Events geht, sehe ich somit das alles (zu?) kritisch.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.