Serialisieren bzw. Umfangreiches Konstrukt in Datei speichern.

  • VB.NET

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von nafets3646.

    Serialisieren bzw. Umfangreiches Konstrukt in Datei speichern.

    Hallo Leute!

    Ich möchte den gesamten Inhalt folgender Struktur in eine Datei speichern und später wieder von der Datei in die Struktur laden:

    VB.NET-Quellcode

    1. <Serializable()> _
    2. Structure TischplanElementeStructure
    3. Dim TablePanelArray As Panel
    4. Dim Tischnummer As Integer
    5. Dim Tischname As String
    6. Dim Color As System.Drawing.Color
    7. Dim TextColor As System.Drawing.Color
    8. Dim links As Integer
    9. Dim oben As Integer
    10. Dim breite As Integer
    11. Dim hoehe As Integer
    12. Dim Aktiv As Boolean
    13. Dim BackgroundImage As Image 'Jedes Grafikelement hat einen Namen
    14. Dim BackgroundImageLayout As Integer
    15. End Structure
    16. Public TischplanElemente(1000) As TischplanElementeStructure


    Ich erhalte beim serialisieren jedoch immer diese Meldung:

    Der Typ "System.Windows.Forms.Panel" in Assembly "System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" ist nicht als serialisierbar gekennzeichnet.

    Wie könnte ich das ganze lösen. Kann man System.Windows.Forms.Panel irgendwie als serializierbar kennzeichnen?
    Oder gibt es eine andere Möglichkeit diese Struktur in eine Datei zu speichern?

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Hi
    haben wir schon mal erwähnt, dass Daten und GUI voneinander zu trennen sind? Das ist, als würdest du beim Ski-Fahren immer den Laden des Verkäufers mit dir herumtragen, weil du ihn ggf. brauchst, um dich später bei ihm zu beschweren (Ok, ist etwas anders, aber man kann's sinngemäß so interpretieren).
    Panel selbst ist kein Datum und damit gehört es auch nicht da rein. Außerdem wäre statt einer Structure eine Klasse zu wählen.

    Gruß
    ~blaze~
    Danke, das befürchtete ich schon.
    Und natürlich habt Ihr recht. Das Panel mitzuschleppen ist keine gute Idee.

    Das Panel muss für die Programmfunktion eigentlich gar nicht mitgespeichert werden habe ich gerade festgestellt. Wird ohnehin aus den übrigen Daten erstellt.

    Ich habe das Panel Objekt nun mal ausgeschlossen (habe das Attribut <NonSerialized()> vorhin erlesen):

    VB.NET-Quellcode

    1. <Serializable()> _
    2. Structure TischplanElementeStructure
    3. <NonSerialized()>
    4. Dim TablePanelArray As Panel
    5. Dim Tischnummer As Integer
    6. Dim Tischname As String
    7. Dim Color As System.Drawing.Color
    8. Dim TextColor As System.Drawing.Color
    9. Dim links As Integer
    10. Dim oben As Integer
    11. Dim breite As Integer
    12. Dim hoehe As Integer
    13. Dim Aktiv As Boolean
    14. Dim BackgroundImage As Image 'Jedes Grafikelement hat einen Namen
    15. Dim BackgroundImageLayout As Integer
    16. End Structure
    17. Public TischplanElemente(1000) As TischplanElementeStructure


    Speichern kann ich das ganze nun auch schon.

    VB.NET-Quellcode

    1. Dim b As New BinaryFormatter
    2. Dim m As New MemoryStream()
    3. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Create, FileAccess.Write)
    4. b.Serialize(m, TischplanElemente)
    5. m.WriteTo(fs)


    Wie sieht dann die Laderoutine aus? Da bin ich noch nicht (ganz) draufgekommen?

    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    ich hab mal für FileInfo und für Stream Extensions gebastelt, für XmlSerialisierung - jetzt auch für Binär-Serialisierung:

    VB.NET-Quellcode

    1. ''' <summary>Achtung! FileInfo.OpenWrite ist ungeeignet, denn es erneuert nicht unbedingt die ganze Datei</summary>
    2. <Extension()> _
    3. Public Sub SerializeXml(ByVal fi As FileInfo, ByVal obj As Object)
    4. Using strm = fi.Open(FileMode.Create)
    5. strm.SerializeXml(obj)
    6. End Using
    7. End Sub
    8. <Extension()> _
    9. Public Sub SerializeXml(ByVal strm As Stream, ByVal obj As Object)
    10. Call (New XmlSerializer(obj.GetType)).Serialize(strm, obj)
    11. End Sub
    12. <Extension()> _
    13. Public Function DeserializeXml(Of T)(ByVal fi As FileInfo) As T
    14. Using strm = fi.OpenRead
    15. Return strm.DeserializeXml(Of T)()
    16. End Using
    17. End Function
    18. <Extension()> _
    19. Public Function DeserializeXml(Of T)(ByVal strm As Stream) As T
    20. Return DirectCast((New XmlSerializer(GetType(T))).Deserialize(strm), T)
    21. End Function
    22. ''' <summary>Achtung! FileInfo.OpenWrite ist ungeeignet, denn es erneuert nicht unbedingt die ganze Datei</summary>
    23. <Extension()> _
    24. Public Sub Serialize(ByVal fi As FileInfo, ByVal obj As Object)
    25. Using strm = fi.Open(FileMode.Create)
    26. strm.Serialize(obj)
    27. End Using
    28. End Sub
    29. <Extension()> _
    30. Public Sub Serialize(ByVal strm As Stream, ByVal obj As Object)
    31. Call (New Runtime.Serialization.Formatters.Binary.BinaryFormatter).Serialize(strm, obj)
    32. End Sub
    33. <Extension()> _
    34. Public Function Deserialize(Of T)(ByVal fi As FileInfo) As T
    35. Using strm = fi.OpenRead
    36. Return strm.Deserialize(Of T)()
    37. End Using
    38. End Function
    39. <Extension()> _
    40. Public Function Deserialize(Of T)(ByVal strm As Stream) As T
    41. Return DirectCast((New Runtime.Serialization.Formatters.Binary.BinaryFormatter).Deserialize(strm), T)
    42. End Function

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

    Warum wird denn das Panel aus den Daten erstellt? Normalerweise verwendet man stattdessen andere Controls oder programmiert ein Control, das die Darstellung übernimmt. Pfade sind über System.IO.Path.Combine zu kombinieren. Innerhalb von Klassen, Strukturen, etc. sollten die Zugriffsmodifikatoren Public, Private, Protected, Protected Friend oder Friend verwendet werden, nicht Dim, da Dim den Zugriff nicht sinnvoll beschreibt. Dim wird innerhalb von Methodenkörpern zur Deklaration von Variablen verwendet. Variablen werden nicht nach außen gegeben, außer über Properties. Arrays sind außerdem schlecht dazu geeignet, solche Elemente nach draußen zu geben, da eine direkte Überwachung des Arrays nicht möglich ist, wenn es nicht gekapselt wird. Listen oder dergleichen, die eine Vererbung und ggf. Datenbindung ermöglichen, sind bei sowas häufig praktischer (bspw. System.ComponentModel.BindingList(Of T)).

    Zur Deserialisierung wird einfach Deserialize aufgerufen und der Typ des Objekts angegeben. Anschließend wird eben das deserialisierte Objekt zum Typ gecastet und kann verwendet werden. Kommt aber auf die Serialisierungsweise an.

    Extensions würde ich da übrigens nicht verwenden, da Binäre Serialisierung, Xml-Serialisierung, etc. sehr konkrete Verfahren sind und damit nicht in allen Bereichen möglicherweise anzutreffen (sind quasi nicht Bezugs-unabhängig).

    Gruß
    ~blaze~
    Danke Leute!

    Ich habe Eure Codebeispiele ausprobiert - irgendwo hakt es immer.

    Für mich die Lösung wäre das "Gegenstück" zu:

    VB.NET-Quellcode

    1. Dim b As New BinaryFormatter
    2. Dim m As New MemoryStream()
    3. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Create, FileAccess.Write)
    4. b.Serialize(m, TischplanElemente)
    5. m.WriteTo(fs)


    Ich müsste also nur den Stream wieder laden und in die Struktur "zurückkopieren".
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Hast du denn das, was wir dir gesagt haben, auch so umgesetzt? Es wäre sehr hilfreich, wenn du erläutern könntest, was genau du wie umgesetzt hast oder zumindest ein paar Worte zu den Sachen verlierst, die wir so verloren haben, weil wir ja nur Vorschläge unterbreiten. Was davon du umsetzt ist ja dir überlassen.

    Gruß
    ~blaze~
    Ehrlich gesagt sind mir Deine Ausführungen zu allgemein und die Häfte davon verstehe ich noch nicht einmal zur Gänze. Ich weis es ist gut von Dir gemeint, aber mit den vielen Fachbegriffen fange ich leider (noch) nicht allzuviel an.


    Mein Code macht (wenn ich das so richtig verstehe):

    Mit dem BinaryFormatter wird Tischplanelemente serialisiert und in den Memorystream(m) geschrieben.
    (m) wird per FileStream gespeichert.

    Ich müsste also den umgekehrten Weg gehen und:

    Den Filestream in Memorystream (m) schreiben und den Memorystream per Deserialize in Tischplanelemente zurückschreiben.
    Wobei man den Filestream eigentlich gleich deserializieren kann (oder ist das falscht)?

    VB.NET-Quellcode

    1. Public Sub TischplanElementeSpeichern()
    2. Dim b As New BinaryFormatter
    3. Dim m As New MemoryStream()
    4. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Create, FileAccess.Write)
    5. b.Serialize(m, TischplanElemente)
    6. m.WriteTo(fs)
    7. fs.Dispose()
    8. m.Dispose()
    9. End Sub
    10. Public Sub TischplanElementeLaden()
    11. If Not File.Exists(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat") Then Exit Sub
    12. Dim b As New BinaryFormatter
    13. Dim Serializer As System.Xml.Serialization.XmlSerializer
    14. Dim fs As System.IO.FileStream = Nothing
    15. fs = New System.IO.FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", IO.FileMode.Open)
    16. b.Deserialize(fs, TischplanElemente)
    17. fs.Dispose()
    18. End Sub


    Der Code ist leider nicht gültig, da bei "b.Deserialize(fs, TischplanElemente)" folgender Fehler gezeigt wird:

    "Der Wert vom Typ "1-dimensionales Array von BONitFlexX.mdl_Hauptmodul.TischplanElementeStructure" kann nicht in "System.Runtime.Remoting.Messaging.HeaderHandler" konvertiert werden."

    Ich könnte zwar die Infos aus der Struktur "Tischplanelemente()" auch einzeln in eine Datenbank schreiben, jedoch wäre das ein viel zu hoher Programmieraufwand für diese selten benötigte Funktion. Hier kommt es auch nicht auf Geschwindigkeit an. Aber wenn alles andere noch komplizierter ist, dann werde ich das mal machen müssen.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    dive26 schrieb:

    Wobei man den Filestream eigentlich gleich deserializieren kann (oder ist das falscht)?
    Dassis schoma richtig.

    Aber ansonsten finde ich dein Code nur wunderlich. Soll das deine Versuche zeigen, die gegebenen Codesnippets zu verwenden? Sorry - ich sehe keine Verbindung zu dem, wassich dir gepostet habe - nur eine weitere Wiederholung des Ansatzes aus dem ersten Post, mit dem du ja nicht weiter kamst.

    und Option Strict On! ist glaub auch nicht.

    und Bitte VB-Tag benutzen - aber richtig
    Hallo ErfinderDesRades!

    Ich habe Deinen Code (hoffentlich) richtig eingebunden. Zuerst bekam ich einige Fehlermeldungen. Als ich dann das 1. Array-Element angegeben hatte, funktionierte der Code. Nun ist es aber so, dass ich nicht nur TischplanElemente(1) speichern und laden möchte, sondern TischplanElemente (1-999).

    Wie mache ich das mit Deinem Code?

    Ich habe versucht nur "Tischplanelemente" zu schreiben, das klappt dann zwar beim Speichern, nicht aber beim Laden. Beim Laden mit [TischplanElemente = Deserialize(Of TischplanElementeStructure)(fs)] bekomme ich folgende Fehlermeldung:

    "Der Wert vom Typ "BONitFlexX.mdl_Hauptmodul.TischplanElementeStructure" kann nicht in "1-dimensionales Array von BONitFlexX.mdl_Hauptmodul.TischplanElementeStructure" konvertiert werden."


    LG Roland
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    VB.NET-Quellcode

    1. <Serializable()> _
    2. Structure TischplanElementeStructure
    3. <NonSerialized()>
    4. Dim TablePanelArray As Panel
    5. Dim Tischnummer As Integer
    6. Dim Tischname As String
    7. Dim Color As System.Drawing.Color
    8. Dim TextColor As System.Drawing.Color
    9. Dim links As Integer
    10. Dim oben As Integer
    11. Dim breite As Integer
    12. Dim hoehe As Integer
    13. Dim Aktiv As Boolean
    14. Dim BackgroundImage As Image 'Jedes Grafikelement hat einen Namen
    15. Dim BackgroundImageLayout As Integer
    16. End Structure
    17. Public TischplanElemente(1000) As TischplanElementeStructure


    Wenns hilft, dann könnte ich Dim TablePanelArray As Panel da rausnehmen und in einem separaten Array ablegen, da ich dieses Control-Array ja nur zur Laufzeit benötige.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    TischplanElementeStructure ?

    VB.NET-Quellcode

    1. Public TischplanElemente(1000) As TischplanElementeStructure
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    wie lautet also der Datentyp?

    naja, kanns auch gleich vorsagen: Also du wirst annehmen, es sei TischplanElementeStructure, aber es ist ein Array von TischplanElementeStructure, und das ist ein Unterschied.

    nu gugge nochma Fehlermeldung, die sagt nämlich genau dasselbe.
    Typ "BONitFlexX.mdl_Hauptmodul.TischplanElementeStructure" kann nicht in "1-dimensionales Array von BONitFlexX.mdl_Hauptmodul.TischplanElementeStructure" konvertiert werden.
    Und wie und wo schreibe ich das dann genau in meinem Programmcode?
    Habe da leider nicht den blassesten Schimmer.

    Wärst Du so nett und schreibts mir die richtig formulierte Programmzeile?

    Vielen lieben Dank.

    Achso, hier mein letzter Code mit Speichern und Laden von nur einem Element des besagten Arrays. Vielleicht kannst Du auf dessen Basis mir die richtige Codezeile(n) zum Speichern und Laden des kompletten Arrays adaptieren?

    VB.NET-Quellcode

    1. Public Sub TischplanElementeSpeichern()
    2. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Create, FileAccess.Write)
    3. Serialize(fs, TischplanElemente(1))
    4. fs.Dispose()
    5. End Sub
    6. Public Sub TischplanElementeLaden()
    7. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Open, FileAccess.Read)
    8. TischplanElemente(1) = Deserialize(Of TischplanElementeStructure)(fs)
    9. fs.Dispose()
    10. End Sub
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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

    naja, wenn du programmieren willst, musst du es imo lernen.
    Da hilfts nix, wenn ich dir die Zeile eben richtig hinschreibe.
    Essentiell ist das Konzept der Datentypen zu verstehen, und dass Datentypen sich unterscheiden, und dass man zB. an eine Variable vom Typ TischplanElementeStructure-Array kein einzelnes TischplanElementeStructure-Objekt zuweisen kann.

    Du bist doch ganz nah dran, das zu kapieren, das wäre alles weggeworfen, wenn mans dir vorsagte.

    Allerdings müsstest du die Codezeile mit dem Fehler wieder in den Post bringen, sonst haben wir nix, worüber wir uns unterhalten.
    Das hilft mir leider nichts.

    Den Code hast Du ja schon im vorigen Post.


    VB.NET-Quellcode

    1. <Serializable()> _
    2. Structure TischplanElementeStructure
    3. Dim PlanNr As Integer
    4. Dim Tischnummer As Integer
    5. Dim Tischname As String
    6. Dim Color As System.Drawing.Color
    7. Dim TextColor As System.Drawing.Color
    8. Dim links As Integer
    9. Dim oben As Integer
    10. Dim breite As Integer
    11. Dim hoehe As Integer
    12. Dim Aktiv As Boolean
    13. Dim BackgroundImage As Image 'Jedes Grafikelement hat einen Namen
    14. Dim BackgroundImageLayout As Integer
    15. End Structure
    16. Public TischplanElemente(1000) As TischplanElementeStructure
    17. Public Sub TischplanElementeSpeichern()
    18. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Create, FileAccess.Write)
    19. Serialize(fs, TischplanElemente(1))
    20. fs.Dispose()
    21. End Sub
    22. Public Sub TischplanElementeLaden()
    23. Dim fs As New FileStream(FlexX_Datenverzeichnis + "Tischplan" + CStr(AktiverPlanInBearbeitung) + ".dat", FileMode.Open, FileAccess.Read)
    24. TischplanElemente(1) = Deserialize(Of TischplanElementeStructure)(fs)
    25. fs.Dispose()
    26. End Sub


    Dort wo ich TischplanElemente(1) schreibe wird jetzt nur das 1. Element des Structur-Arrays geladen und gespeichert. Und statt nur diesem einem möchte ich alle Elemente (in meinem Fall 1-999) speichern. Serialize(fs, TischplanElemente) - also ohne angabe des Array-Elementes funktioniert ja beim Speichern - und die Dateigröße scheint auch entsprechend zu sein, dass wirklich alle Elemente gespeichert wurde, aber beim Laden funktioniert diese Schreibweise (TischplanElemente = Deserialize(Of TischplanElementeStructure)(fs))nicht.

    Klar könnte ich eine Schleife durchlaufen lassen, aber dann hätte ich 999 einzelne Dateien. Das möchte ich auch nicht. Es müsste doch irgendwie mit einer Zeile helfen.

    Du bist doch ganz nah dran, das zu kapieren, das wäre alles weggeworfen, wenn mans dir vorsagte.
    Wenn ich das Ergebnis kennen würde, dann würde ich auch verstehen wie und warum es funktioniert. Für das Try & Error Spielchen habe ich leider nicht die nötige Zeit. Also wenn Du weist ob und wie es geht, dann wäre ich Dir sehr Dankbar für den (nein nicht Hinweis), sondern die korrekt formulierte Codezeile. Denn ich bin mir sicher es ist nur so etwas simples wie "array of irgendwas". Hab aber schon alles durchprobiert und bin nicht draufgekommen. Wenn Du aber schon weist, dass dies nie funktionieren wird, dann bitte auch sagen. Es wäre Schade um die Zeit die wir hier investieren.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

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