Kommunikation zwischen mehreren Forms per Event

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

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

    @roepke Bei mir würde das über Interfaces gehen.
    Ich habe bei mir mehrere Sorten Kameras:
    ICamera
    - Property AlleKameraParameter
    - Function Initialisierung()
    - Sub Quit()
    - Sub Live()
    - Sub StopLive()
    - Function SnapShot()
    usw.
    =====
    Elementare Properties und Prozeduren kommen in die Basis-Klasse, diese können von allen Arten an Hardware bedient werden: Init(), Quit(), ... (Ggf. IsCamera, IsActuator, IsSensor, je nach Philosophie der Ansteuerung)
    Spezielle Hardware einer Art (z.B. Kameras, Aktuatoren, Sensoren, ...) bekommen eigene Interfaces, die von derf Basisklasse abgeleitet sind.
    =====
    Die Kamera-Parameter haben als Basis-Interface "die üblichen Verdächtigen":
    Breite, Höhe, Pixelformat, HasLive, ...
    als Erweiterung dazu:
    HasTemperature, HasHighResolution
    usw.
    =====
    Was Du alles brauchst, wirst Du erst merken, wenn es beim "normalen Arbeiten" fehlt.
    Dann gehst Du in die nächste Version und erweiterst das jeweilige Interface.
    Wenn es etwas sehr spezielles ist, kommt die Property HasXXX dazu, die Hardware, die es hat, antwortet True, alle anderen False (z.B. Color-Kameras).
    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!
    Darum gehts

    ErfinderDesRades schrieb:

    VB.NET-Quellcode

    1. 'Zeigt dieses Steuerelement am Anfang der z-Reihenfolge an.
    2. Friend Shared Sub BringFormToFront(ByVal FormName As String)
    3. My.Application.OpenForms.Cast(Of Form).FirstOrDefault(Function(x) x.Name = FormName)?.BringToFront()
    4. End Sub
    5. 'testet ob das Form mit dem Namen "sFormName" geöffnet ist
    6. Friend Shared Function FormIsOpened(ByVal sFormName As String) As Boolean
    7. Return My.Application.OpenForms.Cast(Of Form).Any(Function(x) x.Name = sFormName)
    8. End Function
    9. 'selektiert das Form von sFormName
    10. Friend Shared Function FormSelect(sFormName As String) As Form
    11. Return My.Application.OpenForms.Cast(Of Form).FirstOrDefault(Function(x) x.Name = sFormName)
    12. End Function

    roepke schrieb:

    Öffne ich nun ein neues Form4 wird geschaut, ob es Platz mit Array gibt

    Ansonsten wird man glaub mit FormName nicht glücklich. Du öffnest mw. 3 mal dein Form4 - welches willste dann nehmen?

    Bzw Frage: Wozu brauchst du sowas - das geht doch sicherlich besser.
    Anners gefragt: Zeig mal Beispiel, wo diese komischen Methoden aufgerufen werden (du siehst, ich habs Sample immer noch nicht gezogen)
    Hallo, nach Wochen der anderweitigen Beschäftigung zurück zu diesem Thema.

    VB.NET-Quellcode

    1. Friend Shared Sub BringFormToFront(ByVal FormName As String)

    soll das neue, geöffnete Form in den Vordergrund bringen. Wird also eine neue Instanz des Forms angelegt und das Form geöffnet ist es im Vordergrund. Klicke ich nun ein anderes Form an, wechselt das aus dem Vordergrund in den Hintergrund. Hiermit kann ich es mir wieder nach vorne holen. Der Aufruf erfolgt a) beim Erstellen des Foms, b) per externem Menü, das mir alle geöffneten Forms in einer Liste anzeigt. Klicke ich dort auf einen Eintrag wird das zugehörige Form in den Vordergund geholt.

    VB.NET-Quellcode

    1. Friend Shared Function FormIsOpened(ByVal sFormName As String) As Boolean

    Soll das mehrfache Öffnen eines Forms verhindern. Sprich öffne ich z.B. ein Form mit Namen "TestForm" soll das vermeiden eine zweite Instanz dieses Forms zu öffnen.
    In meinen Beispiel: Von Form 4 darf ich beliebeig vel Instanzen öffnen, da ist es überflüssig, aber von den übrigen 3 Forms nur jeweils eine.

    VB.NET-Quellcode

    1. Friend Shared Function FormSelect(sFormName As String) As Form

    Ist hier überflüssig. Die Idee war, dass ein Form, das nicht im Vordergrund ist und auch keinen Fokus hat angesprochen werden kann OHNE in den Vordergrund zu rutschen.

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

    Jetzt hab ich aber noch einen:
    - Ich habe ein UserForm erstellt, das verschiedene Events auslöst.
    - Mein Hauptprojekt soll dieses UserForm zu Laufzeit nun mehrfach einbinden, sagen wir z.B. 3x.

    Im Moment binde ich das UserControl so ein:

    VB.NET-Quellcode

    1. Dim WithEvents MyUserControl_evts As New MyUserControl()
    2. Private Sub Button_Click(sender As System.Object, e As System.EventArgs) Handles Button.Click
    3. Dim NewUserControl As New MyUserControl
    4. Me.Controls.Add(NewUserControl)
    5. NewUserControl.Left = 12
    6. NewUserControl.Top = 305
    7. NewUserControl.lbl_UserControlName.Text = "First User Control"
    8. End Sub


    Jetzt will ich aber jedes Mal beim Klicken auf Button eine neue Instanz des UserControls erstellen 8bis zu 3 Stück).
    Frage 1: wie mache ich sowas am sinnvollsten? Mit AddHandler anstelle WithEvents, da ja jede Instanz für sich betrachtet werden muss?
    Denn, jede dieser Instanzen kann Events auslösen.
    Frage 2: wie kann ich dann feststellen welche Instanz es war die das Ereignis ausgelöst hat? (vermutlich klärt sich das mit Antwort auf Frage 1.)
    Frage 3: Es gibt Ereignisse, bei denen es egal ist welche Instanz es war. Kann ich solche Ereignisse irgendnwie zusammenfassen?

    Beim schreiben dieser Zeilen kommt mir gerade eine Idee: anlegen einer Collection würde vermutlich (irgendiwe) funktionieren.

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

    Was passiert in der Prozedur

    roepke schrieb:

    BringFormToFront()
    ?
    Wer ist das Parent dieser Form?
    Hat es Zweck, dieser Form .TopMost = True zu geben?
    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!
    Ich glaube da wird es auch gerade etwas heller.
    BringToFront() bezieht sich auf Controls, oder?
    Sprich, ich könnte damit z.B. einen Button vor ein Label setzen.
    Irgendwie kommt aber auch das Form nach vorne.
    .TopMost bezieht sich auf das Form und bringt dieses nach Vorne.
    Dann ist es wohl eher .TopMost.
    Form1 ist der Schöpfer von Form4 und Form4 soll nach dem Erstellen nach vorne.
    Oder halt wenn ich es in der Liste ausgewählt habe.

    roepke schrieb:

    BringToFront() bezieht sich auf Controls, oder?
    Keine Ahnung.
    Im Designer beszieht sich eine so benannte Prozedur auf Controls.
    Im laufendsen Programm kann sich das auch auf Forms beziehen.
    Deswegen noch einmal:

    RodFromGermany schrieb:

    Was passiert in der Prozedur

    roepke schrieb:

    BringFormToFront()
    ?
    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!
    Das per .Name übergebene Form wird mit allen geöffneten Forms in My.Application.OpenForms verglichen.
    Ist der Vergleich erfolgreich wird das Form in den Vordergrund gebracht.
    Wie aber schon im letzten Beitrag bemerkt, ist BringToFront() wohl nicht richtig, sondern es muss .TopMost sein.
    Das funktioniert zumindest besser, weil es sich auf Forms und nicht auf Controls bezieht.

    VB.NET-Quellcode

    1. Friend Shared Sub BringFormToFront(ByVal FormName As String)
    2. Dim fResult As Form = Nothing
    3. If FormName.Length > 0 Then
    4. For Each oForm As Form In My.Application.OpenForms
    5. If oForm.Name.ToUpper = FormName.ToUpper Then
    6. 'oForm.BringToFront()
    7. oForm.TopMost = True
    8. End If
    9. Next
    10. End If
    11. End Sub
    @roepke das Control.BringToFront() sollte es eigentlich tun, das setze ich auch ein.
    Du kannst ja mal an einem neuen kleinen Projekt diesen Befehl mit sich überlappenden Controls und (nicht modalen) Formen ausprobieren.
    Eine Form ist ja letzten Endes auch "nur" ein Control.
    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: Hab ich schon probiert. BringToFront() funzt auch, verhält sich (gefühlt) aber etwas anders als .TopMost. Mit letzterem habe ich den EIndruck das Form wird mit etwas mehr Vehemenz in den Vordergrund gerückt. Ich benutze keine MsgBoxen, sondern habe mir eigenes Projekt dafür geschrieben, das Nachrichten in aufpoppenden Forms anzeigt. Die geben dann den Fokus nicht so leicht her, wenn der Benutzer nicht die Nachricht irgendwie betstätigt. Mit BringToFront() hüpften die mitunter auch mal wieder unbestätigt in den Hintergrund.

    roepke schrieb:

    Die geben dann den Fokus nicht so leicht her, wenn der Benutzer nicht die Nachricht irgendwie betstätigt.
    In diesem Moment müsstest Du die Form wieder auf .TopMost = False setzen.
    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!
    Im Moment funktioniert das bei mir mit .TopMost ganz gut. Das die Meldung bis zu Quittierung vorne bleibt ist für mich OK. Bei allen anderen Forms muss ich das noch beobachten

    Um nochmal auf meine Frage aus Post 26 zurück zu kommen:

    - Ich habe ein UserForm erstellt, das verschiedene Events auslöst.
    - Mein Hauptprojekt soll dieses UserForm zur Laufzeit nun mehrfach einbinden, sagen wir z.B. 3x.

    Ich hab das jetzt so realisiert:

    Form1 hat einen Button. Jedes mal wenn der Button gedrückt wird, wird eine neue Instanz von Form4 erstellt.
    Eine Info darüber wird in ein Array eingetragen und es werden die Event Handler eingerichtet.

    VB.NET-Quellcode

    1. Dim instForm4(0) As Form4
    2. 'Eine Instanz von Form4 erstellen
    3. Private Sub btnForm1OpenNewInstanceOfForm4_Click(sender As System.Object, e As System.EventArgs) Handles btnForm1OpenNewInstanceOfForm4.Click
    4. Dim iFormInstCounter As Integer = instForm4.GetUpperBound(0)
    5. Dim iCounter As Integer
    6. 'Evtl. Lücken im Array finden
    7. For iCounter = 0 To iFormInstCounter
    8. If instForm4(iCounter) Is Nothing Then
    9. Exit For
    10. End If
    11. Next iCounter
    12. instForm4(iCounter) = New Form4
    13. instForm4(iCounter).Name = "Form4Object_" & iCounter.ToString
    14. instForm4(iCounter).Text = "Form4Object_" & iCounter.ToString
    15. instForm4(iCounter).Show()
    16. instForm4(iCounter).TopMost = True
    17. 'Handler einrichten
    18. AddHandler instForm4(iCounter).evtForm4Close, AddressOf evtForm4Close
    19. AddHandler instForm4(iCounter).evtForm4BtnClick, AddressOf evtForm4BtnClick
    20. 'ggf. Array vergrößern
    21. If iCounter = iFormInstCounter Then
    22. ReDim Preserve instForm4(iFormInstCounter + 1)
    23. End If
    24. End Sub


    Wird eine der Forminstanzen von Form4 nun geschlossen feuert das .Close Ereignis nachfolgendes:

    VB.NET-Quellcode

    1. 'Eine Insatnz von Form4 wurde geschlossen
    2. Private Sub evtForm4Close(ByVal sender As System.Object, ByVal e As Form4EventArgs)
    3. 'Geschlossenes Form aus Array entfernen
    4. For iCounter As Integer = 0 To instForm4.GetUpperBound(0)
    5. If Not instForm4(iCounter) Is Nothing Then
    6. If instForm4(iCounter).Name = e.sFormName Then
    7. RemoveHandler instForm4(iCounter).evtForm4Close, AddressOf evtForm4Close
    8. RemoveHandler instForm4(iCounter).evtForm4BtnClick, AddressOf evtForm4BtnClick
    9. instForm4(iCounter) = Nothing
    10. Exit For
    11. End If
    12. End If
    13. Next iCounter
    14. End Sub


    Das Ereignis auf Form4 ist gegenwärtig auf eine Info beschränkt:

    VB.NET-Quellcode

    1. 'Der Button auf einer beliebigen Form4 Instanz wurde gedrückt
    2. Private Sub evtForm4BtnClick(ByVal sender As System.Object, ByVal e As Form4EventArgs)
    3. For iCounter As Integer = 0 To instForm4.GetUpperBound(0)
    4. If instForm4(iCounter).Name = e.sFormName Then
    5. lblForm1.Text = iCounter.ToString
    6. Exit For
    7. End If
    8. Next iCounter
    9. End Sub


    Die EventArg des Form4

    VB.NET-Quellcode

    1. Public Class Form4EventArgs : Inherits EventArgs
    2. Public ReadOnly sFormName As String
    3. Public Sub New(ByRef sFormName As String)
    4. Me.sFormName = sFormName
    5. End Sub
    6. End Class


    Es müsste doch eigentlich auch mit List(of T) möglich sein.

    VB.NET-Quellcode

    1. Dim instForm4 As List(Of Form4)

    Leider bekomme ich das irgendwie nicht hin.
    Es scheitert schon beim Erstellen der Instanz diese in die Liste per .Add einzutragen
    @roepke Du kannst das FormClose Deiner Form4-Instanz direkt abonieren und musst Dich um sonst nichts mehr kümmern.

    VB.NET-Quellcode

    1. AddHandler instForm4(iCounter).FormClosed, AddressOf evtForm4Close

    VB.NET-Quellcode


    Der Parameter Sender des Events ist eine Form4-Instanz und deren Text-Property oder was sonst noch kannst Du abrufen, wenn Du Sender As Object nach dlg As Form4 castest.
    Mit einer List(Of Form4) bist Du nicht auf eine Anzahl festgelegt.
    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 Super, dass mit direkten Abo des FormClosed Event funzt. Danke dafür.
    Was ich aber irgdnwie nicht ganz hinbekomme ist die Nummer mit der List(of T).
    Wie schon geschrieben scheitere ich am "instForm4.Add(New Form4)" mit "Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."
    List(of T) habe ich bisher nur für Strings und Integer verwendet, noch nie auf Forms.

    VB.NET-Quellcode

    1. 'Form4
    2. Dim instForm4 As List(Of Form4)
    3. 'Eine Instanz von Form4 erstellen
    4. Private Sub btnForm1OpenNewInstanceOfForm4_Click(sender As System.Object, e As System.EventArgs) Handles btnForm1OpenNewInstanceOfForm4.Click
    5. instForm4.Add(New Form4) 'neuen Eintrag am Ende der Liste
    6. 'Raus finden wecleh Index dieser Eintrag hat
    7. Dim iCounter As Integer = instForm4.Count
    8. 'Zusätliche Infos setzen
    9. instForm4(iCounter).Show()
    10. instForm4(iCounter).Name = "Form4Object_" & iCounter.ToString
    11. instForm4(iCounter).Text = "Form4Object_" & iCounter.ToString
    12. AddHandler instForm4(iCounter).FormClosed, AddressOf evtForm4Close
    13. AddHandler instForm4(iCounter).evtForm4BtnClick, AddressOf evtForm4BtnClick
    14. instForm4(iCounter).TopMost = True
    15. End Sub

    roepke schrieb:

    List(of T) habe ich bisher nur für Strings und Integer verwendet, noch nie auf Forms.
    Da gibt es keinen Unterschied.
    Einen Counter brauchst Du nicht:

    VB.NET-Quellcode

    1. Private Sub btnForm1OpenNewInstanceOfForm4_Click(sender As System.Object, e As System.EventArgs) Handles btnForm1OpenNewInstanceOfForm4.Click
    2. Dim dlg As New Form4
    3. instForm4.Add(dl) 'neuen Eintrag
    4. 'Zusätliche Infos setzen
    5. dlg.Name = "Form4Object_" & iCounter.ToString
    6. dlg.Text = "Form4Object_" & iCounter.ToString
    7. dlg.TopMost = True
    8. AddHandler dlg.FormClosed, AddressOf evtForm4Close
    9. AddHandler dlg.evtForm4BtnClick, AddressOf evtForm4BtnClick
    10. dlg.Show()
    11. End Sub
    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!
    @roepke Klar.
    Bewege mal in diesem Zustand ohne den Dialog (mit Esc beenden) die Maus über instForm4.
    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!