Datenaustausch zwischen verschiedenen Forms

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von SilentShadow.

    Datenaustausch zwischen verschiedenen Forms

    Hallo Leute,
    ich habe ein ''kleines'' Problem und hoffe, dass mir hier jemand dabei helfen kann. Es scheint keine große Kunst zu sein, dennoch steh ich gerade hart auf dem Schlauch...

    Folgendes: Ich habe mir eine Anwendung gebaut, die momentan zwei Forms besitzt.
    In der erste Form bzw. in der MainForm lauscht ein TCP-Client, der Daten von meinem TCP-Server empfängt. Die empfangenen Daten lasse ich mir in der MainForm in einer RichTextBox anzeigen.

    Meine zu empfangene Nachricht lautet z.B //SERVER/ARDUINO/WOHNZIMMER/TEMPERATUR@23GRAD/LUFTFEUCHTE@58%

    Diese Nachricht splitte ich mit dem ''/'' bzw ''@'' in ein Array(), damit ich so z.B Ort, Temperaturen und Luftfeuchte extrahieren kann.

    Da ich mir nicht alle Daten in der in MainForm anzeigen lassen möchte, habe ich mir eine zweiten Form mit einer RichTextBox angelegt.

    Nun, wie bekomme ich also die Daten aus dem Array() in der MainForm in der RichTextBox in der zweiten Form angezeigt?

    Lieben Gruß
    silentshadow

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „SilentShadow“ ()

    @SilentShadow Wenn die zweite Form in der ersten instanziiert wurde, gib der zweiten eine entsprechende Methode und ruf die auf.
    Das sieht nach einem nicht modalen Dialog aus.
    Gugst Du hier: Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    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!
    @RodFromGermany Also ich habe mich mal durch deine Informationen geklickt und bin leider noch unschlüssig, wie ich mein Problem lösen kann. Ich hatte mir in meinem zweiten Form schon verschiedene Methoden erstellt um die "RichTextBox" zu füllen. Habe es mit Propertys, Delegaten und öffentlichen Variablen mit gegenseitigen Imports ausprobiert und diese aufgerufen. Führte aber bis jetzt nicht zu meinem Erfolg.

    Die Idee ist momentan eher diese, dass ich mehrere Form-Instanzen aus meiner zweiten Form instanziieren möchte und diese dann wieder über den mitgelieferten fInstance.Name identifizieren zu können, um dann wiedrum die Elemente dieses Forms bedienen zu können.

    Aber geht es nicht irgendwie einfacher? So das sich einfach zwei z.B "RichTextBoxen" über mehrere Forms synchronisieren können?

    Dennoch hier mal der Code, den ich mir bis jetzt zusammengefrickelt habe.

    VB.NET-Quellcode

    1. Private Sub LoadMultipleForms()
    2. OpenFormInstance("Datalogger: Wohnzimmer", "wohnzimmer")
    3. OpenFormInstance("Datalogger: Dachboden", "dachboden")
    4. End Sub
    5. Private Sub OpenFormInstance(fText As String, fName As String)
    6. Dim fInstance As New SecondForm
    7. fInstance.Text = fText
    8. fInstance.Name = fName
    9. If IsFormLoaded(fName) = False Then
    10. fInstance.RichTextBox1.AppendText("FormName: " & fName)
    11. fInstance.ShowDialog()
    12. End If
    13. End Sub
    14. Public Function IsFormLoaded(ByVal sName As String) As Boolean
    15. Dim bResult As Boolean = False
    16. For Each oForm As Form In Application.OpenForms
    17. If oForm.Name = sName Then
    18. bResult = True : Exit For
    19. End If
    20. Next
    21. Return (bResult)
    22. End Function
    @SilentShadow Male mal eine Skizze, woraus hervorgeht, welche Form welche andere Form aufruft und welche Form welche andere Form mit Text bestückt.
    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!
    @SilentShadow Das Parent-Window ruft Methoden auf, das Child-Window sendet Events.
    Mehrere Child-Windows sollten untereinander via Parent-Window kommunizieren.
    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!
    Hallo nochmal^^
    ich habe mal Zeit gefunden mich damit auseinander zu setzen. Ich habe mich entschieden wohl doch keine Forms zu generieren. Stattdessen benutze ich jetzt ein TabControl und generiere mir verschiedene Tabs mit dem zugrundeliegenden DeviceName und darin eine Richtextbox, Textbox und 2 Buttons.
    Wähle ich ein Device Namen aus meiner Listbox aus, kann ich über einen Button einen Tab generieren. Dazu rufe ich über den Button tabcontrolAdd auf und übergebe den Namen für den Tab. Funktioniert. Kann darin dann auch Senden und Empfangen.

    Rufe ich tabcontrolAdd außerhalb des Buttons über z.B einer anderen Sub auf bekomme ich den Fehler: 'Steuerelemente die für einen Thread erstellt wurden, können nicht einem Steuerelement in einem anderen Thread übergeordnet werden.'
    -> TabControl1.TabPages.Add(tabPage)

    Vielleicht hat hier ja jemand einen Tipp! Vielen Dank schon mal...


    VB.NET-Quellcode

    1. Private Sub tabcontrolAdd(deviceName As String)
    2. If Not TabControl1.TabPages.ContainsKey(deviceName) Then
    3. Dim tabPage As New TabPage
    4. tabPage.Text = deviceName
    5. tabPage.Name = deviceName
    6. Dim deviceLog As New RichTextBox
    7. 'Muss Parent vielleicht dynamisch an Tab DeviceName gelinkt werden?
    8. deviceLog.Parent = tabPage
    9. deviceLog.Location = New Point(5, 5)
    10. deviceLog.Size = New Size(445, 500)
    11. deviceLog.Name = deviceName & "_log"
    12. deviceLog.Multiline = True
    13. deviceLog.ReadOnly = True
    14. deviceLog.Enabled = False
    15. Dim deviceCommand As New TextBox
    16. deviceCommand.Parent = tabPage
    17. deviceCommand.Location = New Point(5, deviceLog.Height + 10)
    18. deviceCommand.Size = New Size(240, 20)
    19. deviceCommand.Name = deviceName & "_message"
    20. deviceCommand.Multiline = False
    21. deviceCommand.ReadOnly = False
    22. Dim sendButton As New Button
    23. sendButton.Parent = tabPage
    24. sendButton.Location = New Point(250, deviceLog.Height + 10)
    25. sendButton.Width = 100
    26. sendButton.Height = 20
    27. sendButton.Name = deviceName & "_sendCommand"
    28. sendButton.Text = "Send"
    29. AddHandler sendButton.Click, AddressOf tabcontrolSend
    30. Dim closeConnectionButton As New Button
    31. closeConnectionButton.Parent = tabPage
    32. closeConnectionButton.Location = New Point(350, deviceLog.Height + 10)
    33. closeConnectionButton.Width = 100
    34. closeConnectionButton.Height = 20
    35. closeConnectionButton.Name = deviceName & "_closeConnection"
    36. closeConnectionButton.Text = "Close Connection"
    37. AddHandler closeConnectionButton.Click, AddressOf tabcontrolRemove
    38. ' Hier wird der Fehler von TabControl1.TabPages.Add(tabPage) verursacht.
    39. ' Steuerelemente die für einen Thread erstellt wurden, können nicht einem Steuerelement
    40. ' in einem anderen Thread übergeordnet werden.
    41. ' ControlCollectin.Add und TabPageCollection.Add
    42. TabControl1.TabPages.Add(tabPage)
    43. TabControl1.SelectedTab = tabPage
    44. tabcontrolWrite(deviceName, "----------------------------------------------")
    45. tabcontrolWrite(deviceName, "Session with:" & deviceName)
    46. tabcontrolWrite(deviceName, "----------------------------------------------")
    47. End If
    48. Catch ex As Exception
    49. MsgBox(ex.ToString)
    50. End Try
    51. End Sub
    52. Private Sub tabcontrolRemove(sender As System.Object, e As System.EventArgs)
    53. TabControl1.TabPages.Remove(TabControl1.SelectedTab)
    54. End Sub
    55. Private Sub tabcontrolSend(sender As System.Object, e As System.EventArgs)
    56. Dim deviceName As String = TabControl1.SelectedTab.Name.ToString
    57. For Each tab As TabPage In TabControl1.TabPages
    58. For Each textbox As Control In tab.Controls
    59. If textbox.Name = deviceName & "_message" Then
    60. If textbox.Text.Length > 0 Then
    61. communicationWriter.WriteLine("/arduinocommand " & deviceName)
    62. communicationWriter.WriteLine(RSAMessageVerschlüsseln(textbox.Text.ToString))
    63. tabcontrolWrite(deviceName, textbox.Text.ToString)
    64. message = textbox.Text.ToString
    65. textbox.Text = Nothing
    66. printStatus(TimeOfDay & " >> " & "Command successfully!")
    67. End If
    68. End If
    69. Next
    70. Next
    71. End Sub
    72. Private Sub tabcontrolWrite(deviceName As String, incomingMessage As String)
    73. For Each tab As TabPage In TabControl1.TabPages
    74. For Each richtextbox As Control In tab.Controls
    75. If richtextbox.Name = deviceName & "_log" Then
    76. If incomingMessage.Length > 0 Then
    77. Dim control As RichTextBox
    78. control = richtextbox
    79. control.AppendText(TimeOfDay & " >> " & incomingMessage & vbCrLf)
    80. control.ScrollToCaret()
    81. End If
    82. End If
    83. Next
    84. Next
    85. End Sub

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

    Wie die Fehlermeldung sagt: Du kannst nicht dem TabControl, welches sich "im Main-/GUI-Thread befindet" eine TabPage zuordnen, die Du nebenläufig erstellst, wohl indem Du per TCP-Server/-Client mit Events arbeitest und dann in solch einem Event die o.g. Subs aufrufst. Der EventHandler sollte stattdessen per Invoke diese Erstellungssub aufrufen.
    Was ist das aber für Code? Du hast in Zeile#55/#57 ein (relativ sinnfreies) Catch (Stichwort Fange nur Exceptions ab, die Du kennst und sinnvoll bearbeiten kannst.). Aber wo ist das passende Try dazu?

    btw: Z#2: Ggf. eine Verschachtelungstiefe verringern, indem Du schreibst: If TabControl1.TabPages.ContainsKey(deviceName) Then Exit Sub
    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 Ich bedanke mich für Deine Antwort. Deine Formulierung hat den Nagel nochmals auf den Kopf getroffen und versenkt. Ich rufe das ganze jetzt einfach über "Me.Invoke(New ThreadItemAdd(AddressOf tabcontrolAdd), deviceName)" auf.

    Du hast Recht! Da ist wohl beim Kopieren irgendwo das "Try" verloren gegangen. Die "MsgBox" habe ich nur zum schnellen Debuggen verwendet. Die Exceptions lasse ich mir in der Regel aber separat über ein Methode ausklamüsern und anzeigen.

    Aber Danke für den Link ;)

    Die Änderung der Verschachtelungstiefe habe ich auch mal so von dir übernommen. Macht ja schon Sinn :)

    Dennoch komme ich sofort wieder zurück auf ein neues Problem. Das "tabcontrolWrite(deviceName As String, incomingMessage As String)" erzeugt ein ähnliches Problem. Ich umgehe das ganze jetzt mit "Control.CheckForIllegalCrossThreadCalls = False" aber das ist doch Käse! Das "Invoke" wie oben angewendet funktioniert dort leider nicht. Hat die Lösung da mit der "InvokeMethod" zu tun? Ein Tipp würde reichen ;)

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

    SilentShadow schrieb:

    Die "MsgBox" habe ich nur zum schnellen Debuggen verwendet.
    Selbst wenn Du MessageBox.Show() zum Debuggen verwendest, wäre das suboptimal.
    Gugst Du Debug.WriteLine() und
    Debuggen, Fehler finden und beseitigen
    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!
    Was anderes - bitte mach nicht sowas:

    SilentShadow schrieb:

    VB.NET-Quellcode

    1. [...] TabControl1.SelectedTab.Name.ToString
    2. [...]
    3. [...] textbox.Text.ToString
    Welchen Datentyp hat .SelectedTab.Name?
    Welchen Datentyp hat textbox.Text?
    Warum also diese mit .ToString nach String konvertieren?

    Also bitte immer die Datentypen beachten - das sind viele "Kleinigkeiten", die aber in Summa ein Programm lesbar machen.
    @ErfinderDesRades Also kann ich darauf vertrauen, dass ".Text" mir immer einen String übergibt? Ich dachte mir, ich erzwinge das vorsichtshalber mit .ToString, bevor willkürlich andere Datentypen auftreten!?

    Programm läuft jetzt rund wie ein Rad... ;)
    Hier noch einmal der Source...

    Me.BeginInvoke(New ThreadItemAdd(AddressOf tabcontrolAdd), devicename)
    Me.BeginInvoke(Sub() tabcontrolWrite(deviceName, deviceCommand))

    VB.NET-Quellcode

    1. Private Sub tabcontrolAdd(deviceName As String)
    2. If deviceName = tbdeviceName.Text.ToString Then Exit Sub
    3. If deviceName = "odroid-go" Then Exit Sub
    4. If tbcConnections.TabPages.ContainsKey(deviceName) Then Exit Sub
    5. Dim tabPage As New TabPage
    6. tabPage.Text = deviceName
    7. tabPage.Name = deviceName
    8. Dim deviceLog As New RichTextBox
    9. deviceLog .Parent = tabPage
    10. deviceLog .Location = New Point(5, 5)
    11. deviceLog .Size = New Size(650, 250)
    12. deviceLog .Name = deviceName & "_log"
    13. deviceLog .Multiline = True
    14. deviceLog .ReadOnly = True
    15. deviceLog .Enabled = False
    16. Dim deviceCommand As New TextBox
    17. deviceCommand .Parent = tabPage
    18. deviceCommand .Location = New Point(5, chatLog.Height + 10)
    19. deviceCommand .Size = New Size(440, 20)
    20. deviceCommand .Name = deviceName & "_message"
    21. deviceCommand .Multiline = False
    22. deviceCommand .ReadOnly = False
    23. Dim sendButton As New Button
    24. sendButton.Parent = tabPage
    25. sendButton.Location = New Point(450, chatLog.Height + 10)
    26. sendButton.Width = 100
    27. sendButton.Height = 20
    28. sendButton.Name = deviceName & "_sendMessage"
    29. sendButton.Text = "Send"
    30. AddHandler sendButton.Click, AddressOf tabcontrolSend
    31. Dim closeConnectionButton As New Button
    32. closeConnectionButton.Parent = tabPage
    33. closeConnectionButton.Location = New Point(550, chatLog.Height + 10)
    34. closeConnectionButton.Width = 100
    35. closeConnectionButton.Height = 20
    36. closeConnectionButton.Name = deviceName & "_closeConnection"
    37. closeConnectionButton.Text = "Close Connection"
    38. AddHandler closeConnectionButton.Click, AddressOf tabcontrolRemove
    39. tbcConnections.TabPages.Add(tabPage)
    40. tbcConnections.SelectedTab = tabPage
    41. tabcontrolWrite(deviceName, "----------------")
    42. tabcontrolWrite(deviceName, "Device command console:" & deviceName)
    43. tabcontrolWrite(deviceName, "----------------")
    44. End Sub
    45. Private Sub tabcontrolRemove(sender As System.Object, e As System.EventArgs)
    46. tbcConnections.TabPages.Remove(tbcConnections.SelectedTab)
    47. End Sub
    48. Private Sub tabcontrolSend(sender As System.Object, e As System.EventArgs)
    49. For Each tab As TabPage In tbcConnections.TabPages
    50. For Each textbox As Control In tab.Controls
    51. Dim deviceName As String = tbcConnections.SelectedTab.Name
    52. If textbox.Name = deviceName & "_message" Then
    53. If textbox.Text.Length > 0 Then
    54. communicationWriter.WriteLine(RSAStringEncrypt("/arduinocommand " & deviceName & " /command/" & textbox.Text))
    55. tabcontrolWrite(deviceName, tbdeviceName.Text & ": " & textbox.Text)
    56. textbox.Text = Nothing
    57. printStatus("Transmit private message successfully!")
    58. End If
    59. End If
    60. Next
    61. Next
    62. End Sub
    63. Private Sub tabcontrolWrite(deviceName As String, deviceCommand As String)
    64. For Each tab As TabPage In tbcConnections.TabPages
    65. For Each richtextbox As Control In tab.Controls
    66. If richtextbox.Name = deviceName & "_log" Then
    67. If deviceCommand .Length > 0 Then
    68. Dim control As RichTextBox
    69. control = CType(richtextbox, RichTextBox)
    70. control.AppendText(TimeOfDay & " >> " & deviceCommand & vbCrLf)
    71. control.ScrollToCaret()
    72. tbcConnections.SelectedTab = tab
    73. End If
    74. End If
    75. Next
    76. Next
    77. End Sub

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

    SilentShadow schrieb:

    Also kann ich darauf vertrauen, dass ".Text" mir immer einen String übergibt?
    Wenn .Text vom Typ String ist (was Du ja recherchieren solltest), dann wirst Du auch immer nur einen String bekommen, wenn Du .Text aufrufst. Alles andere ist ausgeschlossen. Oder hast Du schonmal erlebt, dass bei einer Funktion oder Property, die einen bestimmten/zurückgibt Datentyp hat, plötzlich ein anderer rauskam?
    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 Alles klar! Dann noch einmal vielen Dank für deine Erklärung. Ich denke, damit habe ich jetzt auch einen ungefähren Ansatz für die Kommunikation zwischen verschiedenen Forms.

    Immer wenn eine Nachricht von einem Device reinkommt, ploppt jetzt ein Tab auf. :thumbsup: Andersherum kann ich wiederum Schaltbefehle senden. Läuft :rolleyes:

    Screenshot -> IMGUR

    SilentShadow schrieb:

    Screenshot
    Nutze die Datei-Anhangs-Funktionalität des Forums:
    Erweiterte Antwort => Dateianhänge => Hochladen.
    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!
    Hellfire-Requests erzeugen Hellfire-Responses (also fire-and-forget): Du wirfst eine Frage ohne Hintergrund- oder Umgebungsinfos in den Raum und bekommst eine an sich richtige Antwort, die aber nicht passend für Dich ist oder nicht die sinnvollste Lösung darstellst, eben weil die Details fehlen. Jetzt könnte man natürlich sagen, dass die Antworter nach den Details fragen sollten, um einen für Dich passenden Lösungsweg aufzuzeigen. Aber sorry: Das sehe ich nicht als meine Aufgabe - zumindest außerhalb der Geschäftswelt. Ist zwar nicht immer forenfreundlich, aber da für uns nicht abschätzbar ist, was Du für Vorwissen mitbringst, kann es sein, dass eine Hellfire-Response ausreicht, weil Dir nur ein Stichwort fehlt, Du es aber aufgrund Deines Vorwissens einschätzen und umsetzen kannst oder ob das Vorwissen fehlt und Du deshalb in die falsche Richtung steuerst.

    btw: Bilder bitte per [+ Erweiterte Antwort] hochladen.

    SilentShadow schrieb:

    damit habe ich jetzt auch einen ungefähren Ansatz für die Kommunikation zwischen verschiedenen Forms.
    Oh nein. Glaub mir, den hast Du nicht - zumindest nicht in diesem Thread.
    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 Sicherlich hätte ich mehr Informationen in den Raum werfen können, um eine präzisere Antwort erhalten zu können. Aber meine Anforderungen konnte ich bis dahin selbst noch nicht so genau erörtern. :D Wie du schon sagst, nach Details zu fragen ist sicherlich nicht deine Aufgabe, zumindest außerhalb der Geschäftswelt. Ist sicherlich alles freiwillig hier. Das ich jetzt den perfekten Lösungsweg serviert bekomme, habe ich auch nicht unbedingt erwartet. Ihr habt mir alle Informationen gegeben, die ich brauche.

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