WinForms: Probleme beim Datenaustausch zwischen 2 Forms

  • VB.NET

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

    WinForms: Probleme beim Datenaustausch zwischen 2 Forms

    Hallo Community,

    ich hänge mich mal an diesen etwas älteren Beitrag an. Meine Problemstellung ist, dass ich in einem größeren MDI-Projekt, die zuletzt geöffneten Fenster (MDIChild) auf dem Bildschirm, mit Namen und Positionen speichere und beim neuen Programmstart wieder öffnen und anzeigen lasse.
    Beim Neustart lese ich aus der Datenbank Namen und Position(x,y) und verwende dann diese msdn.microsoft.com/de-de/library/bb978905.aspx bereits in Beitrag #2 erwähnte Routine.
    Grundsätzlich werden die Fenster auch richtig angezeigt, wobei ich myform.showdialog() durch myform.show() ersetzt habe, da sonst die Fenster nur kurz gezeigt werden und dann verschwinden.
    Nun habe ich festgestellt, dass wenn man zwischen zwei so geöffneten Fenstern Daten austauscht, dass das eine Fenster das andere nicht erkennt. Fragt man das Fenster mit Klarnamen ab z.B. Formname.Created, so ist das Ergebnis immer False.
    Mit irgendetwas liege ich hier völlig falsch und drehe mich seit Tagen mit zig erfolglosen Versuchen im Kreis, vielleicht hat ja einer von euch die Idee wo mein Denkfehler ist.

    ausgelagert aus Form mittels Variable öffnen ~VaporiZed

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

    @immoso Willkommen im Forum. :thumbup:
    Vielleicht postest Du Dein bereinigtes (ohne bin,obj und vs-Verzeichnisse) und gezipptes Projekt (Erweiterte Antwort - Dateianhänge - Hochladen), dann verstehen wir besser, worum es Dir geht.
    Und schreib, was wir tun müssen, um Deinen Effekt zu reproduzieren.
    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!
    Willkommen im Forum.

    Also grundsätzlich ist's ja ein Designfehlerversuch, wenn MDI-Children versuchen, sich gegenseitig anzusprechen. Die sollten sich nicht kennen. Inter-MDI-Children-Kommunikation ist - falls überhaupt benötigt (!) - über das Elternform zu machen. Welche relevante Notwendigkeit besteht in der Komm zwischen 2 Children?
    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.
    @RodFromGermany Das Projekt ist ein wenig zu umfangreich dafür, aber wenn es notwendig ist könnte ich vielleicht etwas reduziertes nachbauen mit dem man den Effekt nachvollziehen kann.

    @VaporiZed Es handelt sich um eine Mehrfenster-Anwendung, bei der in einigen Fällen bei zwei oder mehreren geöffneten Fenstern, wo es sinnvoll ist und der gleiche Ordnungsbegriff verwendet wird, ein Synchronisation stattfindet. Dies funktioniert wenn die Fenster über das Menü geöffnet werden ohne Probleme, wenn die Fenster beim Prorammstart über die oben angesprochene Routine geöffnet werden geht dies nicht. Es muss also ein Unterschied in der Methode der Fensteröffnung geben. Leider ist mir bisher nicht gelungen herauszufinden wodurch das unterschiedliche Verhalten verursacht wird. Die Verknüpfung der synchronisierten Fenster erfolgt indem z.B. der Ordnungsbegriff von Form1 in das entsprechende Combofeld von Form2 eingetragen wird (Form2.ComboBox1.Text = Combobox1.text) und dann von Form1 die Laderoutine von Form2 gestartet wird (Form2.Felderladen),

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

    Dann warte ich gern auf ein Testprojekt.
    Ich frag mich aber, warum Reflection. Mit Application.OpenForms kommst Du gezielter an alle geöffneten Forms. Und wenn Form1 (das MainForm?) die MDI-Children erzeugt, kann es sich doch dieselbigen auch in einer List(Of Form) merken.
    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.
    Nein Form1 ist in meinem Beispiel keine MainForm. Das MDI-Parent ist der Programmstart, welcher nur ein leerer Container mit einem Menü ist. Über das Menü werden dann die MDI-Child wie in meinem Beispiel Form1 und Form2 geöffnet, welche sich dann in dem Container der MDI-Form befinden. Der Benutzer soll nun die Möglichkeit bekommen, seine Fenster, welche er für seinen Aufgabenbereich immer benötigt, mit Namen und Position abzuspeichern, damit die Anwendung beim nächsten Programmstart diese wieder an der gleichen Stelle automatisch öffnet. Wenn man so will nur eine Komfortfunktion, um dem Anwender zu ersparen bei jedem Programmstart die benötigten Fenster manuell über das Menü zu öffnen und an die Position zu schieben, wo diese sich nicht gegenseitig überdecken. Application.OpenForms listet nach meinem Verständnis nur die bereits geöffneten Forms auf, in meinem Fall müssen die Forms ja erst anhand des Namens (String) geöffnet werden. Deshalb verwende ich die Reflection.
    Ich habe mal ein kleines Projekt hochgeladen welches das Problem verdeutlicht. Über das Menü die Fenster Form1 und Form2 öffnen und dann im Textfeld einer Form etwas eintragen. Beim Drücken des OK Button wird der Test im anderen Fenster im Textfeld eingetragen. Dann beide Fenster schließen und mit der dritten Menüfunktion öffnen. Nun das gleiche nochmal versuchen.

    *EXE-Anhang entfernt*

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Uah! Genauso sollte man es eben nicht machen. Das ganze Form1.Show-Zeugsl* ist genau das Altlastenwerk, was Dir hier um die Ohren fliegt. Wenn Du Simulation formladen bei Neustart anklickst, werden durch Reflection Forminstanzen erschaffen, die parallel/zusätzlich zu Form1 und Form2 existieren. Du hast dann also 5 Forms: Programmstart, Form1, Form2 und die beiden über Reflection erstellten Forms. Und wenn Du dann über Form1.TextBox1.Text = was ändern willst, passiert schon was. Nur nicht dort, wo Du es vermutest. Denn Du erwartest eine Änderung auf der per Reflection erstellten Form1-Instanz. Es wird aber Form1 geändert. Nur wurde eben dieses Form1, welches unsichtbar im Hintergrund schlummert, zu Programmstart vom Compiler mittels des Frameworks selber schon erstellt, genauso Form2.
    Besonders gut sichtbar, wenn Du 2x auf Simulation formladen bei Neustart klickst, dann hast Du 4 MDI-Children plus 2 unsichbare Default-Form-Instanzen. Und wie willst Du da erklären, was Dein Programm macht, wenn es so arbeiten würde, wie Du es denkst?
    Ich fasse mit anderen Worten zusammen:
    Ein Kartengeber legt Dir verdeckt eine Herz-König-Karte (K1) und eine Kreuz-König-Karte (K2) hin. Du packst selber (hier mittels Reflection) eine weitere Herz-König-Karte (K1*) und eine Kreuz-König-Karte (K2*) auf den Tisch. Nun sagst Du dem Kartengeber, dass er K1 vom Tisch verschwinden lassen soll. Was er auch macht. Nur erwartest Du, dass K1* verschwindet. Das passiert aber nicht. Weil Du glaubst, dass K1 und K1* identisch sind. Dem ist aber nicht so.

    * Hier nochmal zum nachlesen: Warum »Form1.Show« und Co. einem irgendwann ins Bein schießen
    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.
    Die Erkenntnis das durch Reflection eine neue zusätzliche Instanz erstellt wird hatte ich natürlich auch schon, darum meine Nachfrage wie man ein MDI-Child beim Programmstart aktivieren kann, von dem nur der Name als String vorhanden ist. Wenn das nicht möglich ist, werde ich damit auch leben können, da es sich wie gesagt nur eine Komfortfunktion handelt.
    So zum Beispiel:

    VB.NET-Quellcode

    1. Public Class Programmstart
    2. Private Sub ToolStripMenuItem1_Click(sender As Object, e As EventArgs) Handles ToolStripMenuItem1.Click
    3. CreateAndShowFormByName("Form1", 0, 0)
    4. End Sub
    5. Private Sub Form2ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles Form2ToolStripMenuItem.Click
    6. CreateAndShowFormByName("Form2", 900, 0)
    7. End Sub
    8. Private Sub SimulationNeustartToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SimulationNeustartToolStripMenuItem.Click
    9. CreateAndShowFormByName("Form1", 0, 0)
    10. CreateAndShowFormByName("Form2", 900, 0)
    11. End Sub
    12. Public Sub CreateAndShowFormByName(FormName As String, X As Integer, Y As Integer)
    13. CreateSingleFormCalled(FormName)
    14. ShowFormCalled(FormName)
    15. PlaceFormCalled(FormName, X, Y)
    16. End Sub
    17. Private Sub CreateSingleFormCalled(FormName As String)
    18. If Me.MdiChildren.Any(Function(x) x.Name = FormName) Then Return
    19. Dim myAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly()
    20. Dim strAssemblyName As String = myAssembly.GetName().Name.ToString
    21. Dim FullName As String = myAssembly.GetType(strAssemblyName & "." & FormName, False, True).ToString
    22. Dim myForm As System.Windows.Forms.Form = CType(myAssembly.CreateInstance(FullName), System.Windows.Forms.Form)
    23. myForm.MdiParent = Me
    24. End Sub
    25. Private Sub PlaceFormCalled(FormName As String, X As Integer, Y As Integer)
    26. Me.MdiChildren.Single(Function(Form) Form.Name = FormName).Location = New Point(X, Y)
    27. End Sub
    28. Private Sub ShowFormCalled(FormName As String)
    29. Me.MdiChildren.Single(Function(x) x.Name = FormName).Show()
    30. End Sub
    31. End Class


    Das Anspechen der TextBox in den Children kannst Du erstmal so gestalten:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Me.MdiParent.MdiChildren.Single(Function(Form) Form.Name = "Form2").Controls.OfType(Of TextBox).First.Text = TextBox1.Text
    4. End Sub
    5. End Class

    Sauberer wäre aber wie gesagt Meldung an Programmstart via Event und Programmstart leitet es ans andere Form weiter.
    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.

    immoso schrieb:

    Ich habe mal ein kleines Projekt hochgeladen welches das Problem verdeutlicht. Über das Menü die Fenster Form1 und Form2 öffnen und dann im Textfeld einer Form etwas eintragen. Beim Drücken des OK Button wird der Test im anderen Fenster im Textfeld eingetragen. Dann beide Fenster schließen und mit der dritten Menüfunktion öffnen. Nun das gleiche nochmal versuchen.
    Ein Fall für formübergreifendes Databinding.
    Mit Herumgrabschen von einem Form ins andere wird man auf Dauer nicht froh.
    Also wenns was grösseres wird ist empfehlenswert, sich mit Datenmodellierung zu beschäftigen, anders verliert man bald den Überblick.
    Das sind jetzt Schlagworte, vermutlich erstmal unbekannt. Bei Interesse fragen.