Form-übergreifendes Databinding an ein typisiertes Dataset

  • VB.NET

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von loeffel.

    Form-übergreifendes Databinding an ein typisiertes Dataset

    Eigentlich hatte ich gedacht, dass ich nach Hilfe duch EdR und VaporiZed das Form-übergreifeden und Klassen-übergreifendes Zugreifen auf ein typisiertes Dataset hinbekommen müsste. Wie sich nun herausstellt war dies leider eine falsche Annahme durch mich ?( . Damit wir es hier besser besprechen können habe ich ein kleines Testprojekt erstellt.
    Was soll das Testprojekt können: Es gibt das Haupt-Form "Form1" und ein Unterform "Form2" und eine Klasse "TestClass" und ein typisiertes Dataset "DataSet1". Von beiden Forms und von der Klasse heraus möchte ich auf das DataSet zugreifen können.
    Mit Hilfe von VaporiZed aus einem anderen Beitrag kann ich schon vom Hauptform und von der Klasse auf das DataSet zugreifen. Der Zugriff vom untergeordneten Fenster funktioniert nicht.
    Hier der Code aus dem Testprojekt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Public DataSet1 As New DataSet1
    4. Public Form2 As Form2
    5. Public TestClass As TestClass
    6. Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
    7. TestClass = New TestClass(DataSet1)
    8. DataSet1.NoiseSource.AddNoiseSourceRow("Quelle0")
    9. DataSet1.NoiseSource.AddNoiseSourceRow("Quelle1")
    10. DataSet1.Wert.AddWertRow(0, 0, DataSet1.NoiseSource(0))
    11. DataSet1.Wert.AddWertRow(1, 11, DataSet1.NoiseSource(0))
    12. DataSet1.Wert.AddWertRow(2, 22, DataSet1.NoiseSource(1))
    13. DataSet1.Wert.AddWertRow(3, 33, DataSet1.NoiseSource(1))
    14. End Sub
    15. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    16. Dim OutputLines As New List(Of String)
    17. OutputLines.Clear()
    18. OutputLines.Add("vvvvvvvvvvvvvvvv")
    19. For Each wert In DataSet1.NoiseSource(0).GetWertRows
    20. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    21. Next
    22. OutputLines.Add("----------------")
    23. For Each wert In DataSet1.NoiseSource(1).GetWertRows
    24. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    25. Next
    26. OutputLines.Add("###############")
    27. Label1.Text = (String.Join(Environment.NewLine, OutputLines))
    28. End Sub
    29. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    30. MessageBox.Show(TestClass.Infotext())
    31. End Sub
    32. Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    33. Using frm = New Form2 '(DataSet1) Das klappt nicht sinnvoll
    34. Dim result = frm.ShowDialog
    35. End Using
    36. End Sub
    37. End Class
    38. ' #########################################################
    39. Public Class Form2
    40. Dim _DataSet_Form2 As DataSet1
    41. 'Public Sub New(DataSetToUse As DataSet1) ' Geht bei mir nicht
    42. ' _DataSet_Form2 = DataSetToUse
    43. 'End Sub
    44. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    45. Dim OutputLines As New List(Of String)
    46. OutputLines.Clear()
    47. OutputLines.Add("vvvvvvvvvvvvvvvv")
    48. For Each wert In _DataSet_Form2.NoiseSource(0).GetWertRows
    49. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    50. Next
    51. OutputLines.Add("----------------")
    52. For Each wert In _DataSet_Form2.NoiseSource(1).GetWertRows
    53. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    54. Next
    55. OutputLines.Add("###############")
    56. Label1.Text = (String.Join(Environment.NewLine, OutputLines))
    57. End Sub
    58. End Class
    59. ' ###########################################################
    60. Public Class TestClass
    61. Dim _DataSet_TestClass As DataSet1
    62. Public Sub New(DataSetToUse As DataSet1)
    63. _DataSet_TestClass = DataSetToUse
    64. End Sub
    65. Public Function Infotext() As String
    66. Dim OutputLines As New List(Of String)
    67. OutputLines.Clear()
    68. OutputLines.Add("vvvvvvvvvvvvvvvv")
    69. For Each wert In _DataSet_TestClass.NoiseSource(0).GetWertRows
    70. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    71. Next
    72. OutputLines.Add("----------------")
    73. For Each wert In _DataSet_TestClass.NoiseSource(1).GetWertRows
    74. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    75. Next
    76. OutputLines.Add("###############")
    77. ' MessageBox.Show(String.Join(Environment.NewLine, OutputLines), "Werte " & ENR_Nr.ToString)
    78. Return (String.Join(Environment.NewLine, OutputLines))
    79. End Function
    80. Public Sub Testausgabe()
    81. Dim OutputLines As New List(Of String)
    82. OutputLines.Clear()
    83. For Each wert In _DataSet_TestClass.NoiseSource(1).GetWertRows
    84. OutputLines.Add(wert.Frequenz.ToString & " " & wert.ENR_dB.ToString)
    85. Next
    86. MessageBox.Show(String.Join(Environment.NewLine, OutputLines), "Werte")
    87. End Sub
    88. End Class


    Von EdR habe ich noch einen anderen Tip bekommen: Daten laden, speichern, verarbeiten - einfachste Variante
    Leider helfen mir diese Hinweise aus Beitrag #7 auch nicht weiter um vom Form 2 auch auf das Dataset zugreifen zu können.

    Könnt ihr mir bitte weiterhelfen?

    Verschoben. ~Thunderbolt
    Dateien
    • TestDataset.zip

      (274,56 kB, 133 mal heruntergeladen, zuletzt: )

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

    Da reicht mir schon der Code, da brauch ich gar nicht Dein Projekt runterzuladen. Es gibt 2 Möglichkeiten. Wenn Du in Form2 nur eine Zeile des tDS bearbeiten willst, dann übergib die an Form2. Wenn es das ganze tDS sein soll, dann ... tja, 3x darfste raten. Richtig! Du übergibst das gesamte tDS, so wie Du es für die Testklasse in Zeile#74 auch gemacht hast. Denn Form2 ist wie die Testklasse doch auch nur eine Klasse. Das mal ganz grob für den Abend. Morgen geh ich (vielleicht) noch ins Detail, falls notwendig.
    Öhm ... Achso. Weil Du gerade diesen Vorschlag schon verworfen hast. Was funktioniert denn daran nicht? Und sollte es wirklich nicht klappen (ich weiß nur grad nicht, warum das so sein sollte), tja, dann machst Du Dir ne Friend Sub in Form2:

    VB.NET-Quellcode

    1. Friend Sub SetDataSet(Tds As DataSet1)
    2. Me.DataSet1 = Tds
    3. End Sub

    und rufst diese Sub nach dem Using (Zeile#41) auf.
    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.
    Das mit der Übergabe wie in Zeile #74 hatte ich auch verscuht und dann haben sich die Controls in Form2 irgendwie nicht mehr richtig geöffnet und ich hatte ein leeres Form. Wie auch immer - vielleicht hatte ich da auch irgendeinen Fehler eingebaut... Das sollten wir uns morgen vielleicht nochmals vornehmen.

    Ich habe gerade noch einen anderen Weg gefunden, kann aber nicht beurteilen ob er empfehlenswert ist.
    Im Deisgner von Form2 habe ich unter Toolbox-TestDataset-Komponenten mein Dataset1 gefunden und mit der Maus ins Form2 gezogen. Daraufhin wurde ein Dataset11 erstellt. Im Code von Form2 habe ich dann diese Sub eingefügt:

    VB.NET-Quellcode

    1. Private Sub Form2_Shown(sender As Object, e As EventArgs) Handles MyBase.Load
    2. DataSet11 = Form1.DataSet1
    3. End Sub

    Nun scheint es alles richtig zu funktionieren. Ist das aber dann noch ein typisierter Zugriff oder hat dieser Weg irgendwelche Nachteile?

    Deinen Vorschlag mit der Friend Sub bekomme ich bei mir nicht zum Laufen. Sorry.
    Wenn Du tatsächlich nur schreibst

    VB.NET-Quellcode

    1. Public Class Form2
    2. Dim _DataSet_Form2 As DataSet1
    3. Public Sub New(DataSetToUse As DataSet1)
    4. _DataSet_Form2 = DataSetToUse
    5. End Sub

    dann geht das deshalb nicht, weil da eine Zeile nicht mehr drinsteht, die für Formulare sehr wichtig ist und normalerweise automatisch hinzufegügt wird: InitializeComponent. Ohne die wird die Form2.Designer.VB nicht vollständig aufgerufen und das führt auch schon zur Designzeit dazu, dass Du nicht mehr vernünftig arbeiten kannst. Weil VS jenes New und normalerweise auch InitializeComponent aufruft, um das Formular im Designer anzuzeigen. Fehlt der Aufruf jener Prozedur, weiß VS gar nicht mehr, wie es das Formular zeigen soll, da dort das komplette Erst-Aussehen etc drinsteckt.
    Ich bastel mal ne TestApp mit allen möglichen Zugriffen.

    Deine Methode ist scheinbar eine funktionierende. Aber leider nur scheinbar. Tatsächlich kannst Du Dir damit später ziemlich Probleme einhandeln. 1. Wenn Du so arbeitest, warum nutzt Du dann nicht auch in Zeile#41-#43 einfach Form2.Show (bevor sich die anderen Forenuser diesbezüglich zu Wort melden, wird egon das sicherlich gut beantworten können; diese Begründung ist wichtig). 2. (aber bitte erst reinschauen, wenn Du Frage 1. beantwortet hast) gebe ich meinen Senf in einem anderen Thread dazu.
    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.
    Guten Morgen VaporiZed. Das wird jetzt wieder ein ganz wichtiges Thema für mich, damit ich mir nicht auf lange Zeit immer wieder selbst ins Knie schieße. Danke.
    Zu deiner Frage warum ich frm.ShowDialog und nicht einfach nur Show bisher verwendet habe. In dem zweiten Form sollen Einstellungen für das Hauptprogramm getätigt werden können. In dieser Zeit sollen aber keine Eingaben im Hauptprogramm erledigt werden dürfen. Man soll diese Veränderungen aber sofort in Form1 sehen können. Es sollen also nicht Form1 und Form2 gleichzeitig bedient werden können. Wenn Form 2 aufgerufen wird soll Form1 "optisch readonly" sein - also ein modaler Dialog. (Sollte meine Wünsche vom üblichen Vorgehen abweichen bleibe ich für Anregungen natürlich offen.)
    Wie dir bekannt ist, werden bei mir in Form1 Messwerte dargestellt. In dem zweiten Fenster sollen dann z.B. Einstellungen für das Chart (Achseneinstellungen) oder eine Datenmanipulation möglich sein. Später soll dann noch eine Messwerterfassung im Hintergrund in einem anderen Thread erfolgen. Da sollten die Zugriffe schon korrekt erfolgen. Mir ist jetzt schon aufgefallen, dass meine bisherigen Zugriffe mit ShowDialog (so wie ich sie durchgeführt hatte) nicht korrekt waren, konnte mir aber nicht selbst helfen. Auf deine TestApp mit allen möglichen Zugriffen bin ich gespannt. Das ist das was mir sehr helfen würde.
    (Du hast bestimmt im Hintergrund mitverfolgt, dass ich nun mit MySettings Einstellungen im Programmverzeichnis abspeichern kann.)

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

    Stop. Meine Frage sollte lauten: Warum benutzt Du

    VB.NET-Quellcode

    1. Using frm = New Form2 '(DataSet1) Das klappt nicht sinnvoll
    2. Dim result = frm.ShowDialog
    3. End Using

    und nicht stattdessen einfach nur

    VB.NET-Quellcode

    1. Form2.ShowDialog

    Dass Du es so machen solltest, nämlich mit dem Using, ist richtig. Nur weißt Du auch, warum das richtig ist?
    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.
    >>> Nur weißt Du auch, warum das richtig ist?
    Nur zur Hälfte und nicht vollständig. Ich habe es im Forum in einem Beitrag von EdR gefunden. In meinen Büchern wird nur Form2.Show oder Form2.ShowDialog verwendet.
    Mittlerweile lese ich maches nochmals durch. Vor rund drei Wochen bin ich noch von vielen Beiträgen inhaltlich überrollt worden.

    Hier im Forum habe ich irgendwo gelesen, dass mit dem "Using" nicht mehr gebrauchte Klasse vollständig wieder freigegeben werden. Da ich viele Dinge noch nicht richtig überblicke hört sich das für mich vernünftig an. Weiteres Wissen ist aber nicht vorhanden, nur dass es eine gewisse Ähnlichkeit mit Try hat. An welcher Stelle ist dieses vollständige Freigeben wichtig und wo könnte es zu Problemen führen, wenn man es nicht macht?

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

    Habes kurz angeschaut.

    Ich hab mir mal zur Visualisierung 2 DGV zurechtgestellt. (Die wären nachher wieder zum löschen)
    Immerhin sieht man mal so die Daten die in das Dataset geschufelt werden.

    In der Form1, habe ich das Dataset gleich mit dem Designer erstellt.
    Es gibt zwei Zugriffe auf Form2. Einmal mit dem Dataset, und einmal mit me.
    In der 3. Form habe ich einen Handler + und das Dataset übergeben, zum zeigen was auch noch geht. Die Übergabe des Datasets muss aber bestehen, sonst werden die Daten auf der Form3 nicht aktualisiert.

    Freundliche Grüsse

    exc-jdbi
    Dateien
    • TestDataset2.zip

      (32,12 kB, 144 mal heruntergeladen, zuletzt: )
    OK, exc-jdbi war schneller. Das wichtigste ist drin - auch wenn ich den Sinn der Form-Übergabe mittels Me nicht verstehe. Es reicht doch, das tDS zu übergeben.
    btw: Warum eigentlich ByRef in Public Sub New(ByRef _frm1 As Form1)? Form1 ist doch ne Klasse, da bekommt man doch bei ByRef und ByVal das Gleiche. Oder steh ich grad auf'm Gartenschlauch?
    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.
    sorry @VaporiZed

    Als ich reingeschaut habe, und noch niemand was geschrieben hat, hab ich mir gedacht ich maches kurz. Ich werde nächtes man länger warten.

    Die Übergabe bei New ist natürlich Referenziert, da hast du recht. Ich schreibe es immer explizit mit ByRef nochmals hin, damit ich auch gleich weiss, dass es sich um eine referenzierte Parameter-Übergabe handelt.

    Habs das sogar so oben hingeschrieben, in der Zip.

    Freundliche Grüsse

    exc-jdbi
    [meine bücher...]
    Warum so viele? Der Löffelmann täte reichen.
    Den Theiss bitte sofort wegschmeissen - das ist ein Autor, der ein Objekt nicht von einer Klasse unterscheiden kann, und einen String nicht von einem Integer.

    Und im Löffelmann ist dir solche Gurkerei vorgehampelt worden?

    VB.NET-Quellcode

    1. Form2.ShowDialog
    Ich halte eiglich recht viel von Löffelmann - da wär ich echt enttäuscht.

    Den 3. deiner Autoren kenne ich nicht.
    Nee, keine Sorge. Löffelmann arbeitet sauber:
    Seite 549/550:

    VB.NET-Quellcode

    1. Dim resultForm As New Form With {.Text = "Ergebnisliste"}
    2. [...]
    3. resultForm.ShowDialog()

    Und ab Seite 724 hat er extra ein Kapitel dafür: »Formulare ohne Instanziierung aufrufen«, wo es darum geht, dass sowas wie Form2.Show möglich ist, aber er erklärt auch genau, was da wirklich im Hintergrund passiert. Der Rest des Buches ist diesbezüglich auch sauber.

    @exc-jdbi: Kein Thema, ist ja hier kein Exklusivrecht, in diesem Thread zu schreiben. Ich erhebe keinen Anspruch auf alleinige Erklär-Bär-Rolle ;) . Von daher: Schreib ruhig, wenn Dir danach ist.
    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.
    Genauso wie aus Form1*. Aber Achtung! Geht es Dir um TestClass als Klasse oder als Klasseninstanz? Denn Form1* hat seine eigene TestClassinstanz. Auf die kann Form2* natürlich nicht einfach so zugreifen. Wo kämen wir denn da hin? Das würde der Kapselung in der OOP widersprechen.

    Also gibt es mehrere Möglichkeiten:
    • Form2* kann also entweder seine eigene TestClass-Instanz erstellen; damit schwirren mehrere Instanzen rum (eine in Form1*, eine in Form2*)
    • Form1* kann bei Erzeugung von Form2* seine TestClass-Instanz mitgeben (wie bereits mit der DataSet-Instanz geschehen)
    • Form2* kann Form1* später lieb um dessen TestClass-Instanz per Event bitten. Das wär der etwas aufwendigere Weg.
    *hier meine ich die Form-Instanzen, nicht die Klassen an sich
    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.
    Der erste Weg (jeder hat seine Instanz) ist meist nicht so prickelnd. Du willst bestimmt das selbe TestClass-Objekt in beiden Formularen bearbeiten. Daher nur Weg 2 und 3.

    Weg 2 hingegen führt dazu, dass Form2 von Form1 pauschal dessen TestClass-Instanz bekommt. Und zwar egal, ob Form2 die jetzt nun wirklich braucht oder nicht. Es ist ein bequemer Weg, der die Gestaltungsmöglichkeiten erweitert. Er hat aber einen Nachteil. Wenn es nicht mehr nur um ein Objekt geht, sondern und 10, 20, 100, dann wird's sinnfrei. Form1 übergibt zig Objekte, nur damit Form2 die Möglichkeit hat, diese Objekte zu nutzen. Das bläht Konstruktoren auf oder erzeugt haufenweise zusätzliche Funktionen. Klar, man könnte sagen: "Was soll's? Viele Freiheiten, die ich vielleicht mal nutzen will." Aber das fällt unter YAGNI und ist daher zu vermeiden. Bei Objekten, die definitiv designbedingt von einem Formular gebraucht werden, kann also dieser Weg genutzt werden. Aber eben nicht übertreiben.

    Weg 3 ist m.E. immer dann sinnvoll, wenn man eine sehr strikte Klassentrennung erreichen will, die bewirkt, dass Form2 nur dann Daten von Form1 bekommen soll, wenn es wirklich notwendig ist. Also wie bereits bei Weg 2 beschrieben: Form1 hat 100 Objekte im Sortiment, Form2 braucht aber nur 3 davon. Und auch nicht immer.

    Ja, ich könnte das einbauen, aber nicht mehr heute. Ich weiß auch nicht, ob das so sinnvoll ist. Schau doch erstmal, welchen Weg Du brauchst. Ich vermute Weg 2. Aber den kennst Du ja schon, da exc-jdbi den schon eingebaut hat. Und die anderen? Wenn Du die jetzt siehst, denkst Du Dir "aha" und vergisst sie bald wieder, weil Du sie eh nicht verwendest. Ich würde es an Deiner Stelle dann anschauen, wenn Du glaubst, dass sie vom Prinzip her besser passen als Weg 2.
    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.
    Nun, angenommen Du hast Folgendes:

    VB.NET-Quellcode

    1. Public Class TestClass
    2. Public TestInteger As Integer = 0
    3. End Class
    4. Public Class Form1
    5. Private TCI As New TestClass
    6. Public Sub ModifyTCI()
    7. TCI.TestInteger = 1
    8. End Sub
    9. Public Sub CreateAndShowForm2
    10. Using Frm2 As New Form2
    11. Frm2.ShowDialog()
    12. End Using
    13. End Sub
    14. End Class
    15. Public Class Form2
    16. Private TCI As New TestClass
    17. Public Sub New()
    18. MyBase.New()
    19. InitializeComponent()
    20. TCI.TestInteger = 3
    21. End Sub
    22. End Class

    Dann passiert nach Erzeugung und Änderung des TCI-Testintegers in Form2 was mit dem TCI-Testinteger in Form1? Richtig. Gar nix. Da TCI-TestClass ein anderes Objekt ist als TCI-TestClass in Form1. Das ist das gleiche wie mit den DataSets. Nur weil jedes Formular sein eigenes Objekt namens DataSet1 hat, ist es nicht automatisch das selbe, sondern (ganz zum Anfang nur) das gleiche. Es sind eben voneinander unabhängige Objekte. Ändert man den DataSet-Inhalt in Form1, interessiert es das DataSet in Form1 nicht die Bohne. Das ist als ob Alfons einen schwarzen Graphitstift/Bleistift der Marke SuperBlack mit der Länge 10 cm hat und Berta hat auch einen Graphitstift/Bleistift der Marke SuperBlack mit der Länge 10 cm. Wenn Alfons nun seinen Stift anspitzt, passiert ja nicht automatisch was mit dem Stift von Berta, da dies zwar beide zum Anfang gleiche Objekte sind, aber sich eben unabhängig voneinander entwickeln können. Das ist "Weg 1". Wenn Du diesem Weg was abgewinnen kannst, weil er zu Deinem Projekt passt, nutze ihn.
    Was scheitert denn bei Deinen Weg-2-Versuchen?
    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.