XML von unterschiedlichen ViewModels (und Models) laden und speichern

  • WPF

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von flori2212.

    XML von unterschiedlichen ViewModels (und Models) laden und speichern

    Hallo liebes Forum.

    Ich habe ein WPF Projekt, in dem gibt es Models und ViewModels
    Nun möchte ich die Programmdaten in einer XML Datei speichern und daraus auch wieder laden.
    Wie man eine XML Datei serialisiert weiß ich grundsätzlich, allerdings wurde mir in dem Thread folgendes empfohlen:

    ​Das Model ist ja jetzt im Moment eher für die Serialisierung in mehrere XMLs optimiert. Würde ich auch so machen wenn du keine Multiuserumgebung benötigst.
    Damit du da auf der sicheren Seite bist würde ich eine Signleton Klasse machen welche mir das laden und speichern abnimmt und mir immer den aktuellsten Container zurückliefert.


    Ich benötige keine MuliUserumgebung, also benutze ich die XML Serialisierung . Ich verstehe allerdings nicht, was mit einer
    Singleton
    Klasse gemeint ist (ich hab was im Forum gelesen von @ErfinderDesRades, allerdings nicht ganz verstanden wofür man das braucht)

    Außerdem ist mir nicht ganz klar ob ich die Daten aus dem Model oder ViewModel speichere (ich würde jetzt mal auf das Model tippen, da das ViewModel ja zum anzeigen ist)

    Ein Beispiel für eine Model-Klasse:

    C#-Quellcode

    1. ​Namespace Model
    2. Public Class Consumer
    3. Public Property ID As Integer
    4. Public Property RoomID As Integer
    5. Public Property DeviceID As Integer
    6. Public Property DataCollectorID As Integer
    7. Public Property TimeAreaID As Integer
    8. Public Property DeviceCount
    9. End Class
    10. End Namespace


    Und hier die zugehörige ViewModel Klasse:

    C#-Quellcode

    1. ​Namespace ViewModel
    2. Public Class ConsumerViewModel
    3. Inherits ViewModelBase
    4. Private ReadOnly _consumerModel As Model.Consumer
    5. Friend Sub New(consumerModel As Model.Consumer, aviableData As (Devices As List(Of ViewModel.DeviceViewModel), Rooms As List(Of ViewModel.RoomViewModel), DataCollectors As List(Of ViewModel.DataCollectorViewModel), TimeAreas As List(Of ViewModel.TimeAreaViewModel), DeviceGroups As List(Of Model.DeviceGroup)))
    6. _consumerModel = consumerModel
    7. _aviableRooms = aviableData.Rooms
    8. _aviableDevices = aviableData.Devices
    9. _aviableTimeAreas = aviableData.TimeAreas
    10. _AviableDataCollectors = aviableData.DataCollectors
    11. Device = AviableDevices.Where(Function(x) x.ID = _consumerModel.DeviceID).SingleOrDefault()
    12. Room = AviableRooms.Where(Function(x) x.ID = _consumerModel.RoomID).SingleOrDefault()
    13. DataCollector = AviableDataCollectors.Where(Function(x) x.ID = _consumerModel.DataCollectorID).SingleOrDefault()
    14. TimeArea = AviableTimeAreas.Where(Function(x) x.ID = _consumerModel.TimeAreaID).SingleOrDefault()
    15. _deviceCount = _consumerModel.DeviceCount
    16. End Sub
    17. Public ReadOnly Property ID As Integer
    18. Get
    19. Return _consumerModel.ID
    20. End Get
    21. End Property
    22. Private _deviceCount As Integer
    23. Public Property DeviceCount As Integer
    24. Get
    25. Return _deviceCount
    26. End Get
    27. Set(value As Integer)
    28. _deviceCount = value
    29. RaisePropertyChanged()
    30. End Set
    31. End Property
    32. Private _aviableRooms As List(Of ViewModel.RoomViewModel)
    33. Public ReadOnly Property AviableRooms As List(Of ViewModel.RoomViewModel)
    34. Get
    35. Return _aviableRooms
    36. End Get
    37. End Property
    38. Private _aviableDevices As List(Of ViewModel.DeviceViewModel)
    39. Public ReadOnly Property AviableDevices As List(Of ViewModel.DeviceViewModel)
    40. Get
    41. Return _aviableDevices
    42. End Get
    43. End Property
    44. Private _AviableDataCollectors As List(Of ViewModel.DataCollectorViewModel)
    45. Public ReadOnly Property AviableDataCollectors As List(Of ViewModel.DataCollectorViewModel)
    46. Get
    47. Return _AviableDataCollectors
    48. End Get
    49. End Property
    50. Private _aviableTimeAreas As List(Of ViewModel.TimeAreaViewModel)
    51. Public ReadOnly Property AviableTimeAreas As List(Of ViewModel.TimeAreaViewModel)
    52. Get
    53. Return _aviableTimeAreas
    54. End Get
    55. End Property
    56. Private _room As ViewModel.RoomViewModel
    57. Public Property Room As ViewModel.RoomViewModel
    58. Get
    59. Return _room
    60. End Get
    61. Set(ByVal Value As ViewModel.RoomViewModel)
    62. _room = Value
    63. _consumerModel.RoomID = Value.ID 'In das 'originale' Modelobjekt die ID zurückgreiben da sich der Raum ja geändert hat
    64. RaisePropertyChanged()
    65. End Set
    66. End Property
    67. Private _DataCollector As ViewModel.DataCollectorViewModel
    68. Public Property DataCollector As ViewModel.DataCollectorViewModel
    69. Get
    70. Return _DataCollector
    71. End Get
    72. Set(value As ViewModel.DataCollectorViewModel)
    73. _DataCollector = value
    74. _consumerModel.DataCollectorID = value.ID
    75. RaisePropertyChanged()
    76. End Set
    77. End Property
    78. Private _TimeArea As ViewModel.TimeAreaViewModel
    79. Public Property TimeArea As ViewModel.TimeAreaViewModel
    80. Get
    81. Return _TimeArea
    82. End Get
    83. Set(value As ViewModel.TimeAreaViewModel)
    84. _TimeArea = value
    85. _consumerModel.TimeAreaID = value.ID
    86. RaisePropertyChanged()
    87. End Set
    88. End Property
    89. Private _device As ViewModel.DeviceViewModel
    90. Public Property Device As ViewModel.DeviceViewModel
    91. Get
    92. Return _device
    93. End Get
    94. Set(value As ViewModel.DeviceViewModel)
    95. _device = value
    96. _consumerModel.DeviceID = value.ID
    97. RaisePropertyChanged()
    98. End Set
    99. End Property
    100. End Class
    101. End Namespace



    Ich habe jetzt natürlich noch mehr Model und ViewModel Klassen (wie z.B. "Device" oder "Room")

    Ich würde mich sehr über einen Ansatz freuen, wie ich die Daten speicher und lade und über eine kurze Erklärung von Singleton und warum man das beim Datenspeichern braucht.

    Viele Grüße
    Florian
    ----

    WebApps mit C#: Blazor
    Hallo

    Eine Singleton Klasse ist eine Klasse welche nur 1x instanziiert werden kann. Das geht weil der Konstruktor Private ist. So muss die Instanz nicht immer weitergereicht werden. Du kannst somit von überall aus immer auf die selbe instanz zugreifen.
    Es ist schon richtig das das was ein ViewModel abbildet zum anzeigen verwendet wird. Allerdings befüllt du ja auch jetzt schon deine Collections mit den Daten. Eben nur mit Testdaten.

    Später befüllst du es mit den "echten" Daten aus der XML. Das laden und speichern übernimmt dir komplett die Signleton Klasse. Ich nenne solche Klassen immer gerne "Services".
    Im ViewModel rufst du die Daten dann ab und befüllst deine Collections damit.

    Beispiel für eine Signleton-Klasse:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Namespace Services
    2. Public Class ConsumerDataService
    3. Private Sub New()
    4. End Sub
    5. Public Property XmlFolderPath As String
    6. Public Shared ReadOnly Property Instance As ConsumerDataService = New ConsumerDataService
    7. Public Property Consumers As List(Of Model.Consumer)
    8. Public Property Devices As List(Of Model.Device)
    9. Public Property Rooms As List(Of Model.Room)
    10. Friend Sub LoadAllData()
    11. CheckForXmlFolderPath()
    12. 'Laden von Rooms
    13. 'Laden von Devices
    14. 'Laden von Consumers
    15. End Sub
    16. Friend Sub SaveRooms(Optional roomList As List(Of Model.Room) = Nothing)
    17. CheckForXmlFolderPath()
    18. If roomList IsNot Nothing Then Rooms = roomList
    19. 'Rooms Property Serialisieren
    20. End Sub
    21. 'Das selbe für alle anderen Properties
    22. '...
    23. '...
    24. '...
    25. Friend Function ReloadRooms() As List(Of Model.Room)
    26. CheckForXmlFolderPath()
    27. Rooms = 'Deserialisieren von allen Räumen
    28. Return Rooms
    29. End Function
    30. 'Des selbe mit allen anderen
    31. '...
    32. '...
    33. '...
    34. 'Wenn man will kann man nun noch auch noch Spezialdinge mit hier reinpacken wie z.b.
    35. Friend Function GetAllUnusedDevices() As List(Of Model.Device)
    36. CheckForXmlFolderPath()
    37. 'Jetzt z.b. in einer schleife nachsehen ob es Devices gibt welche in keinem Consumer enthalten sind. Nur als Beispiel
    38. End Function
    39. Private Sub CheckForXmlFolderPath()
    40. If String.IsNullOrEmpty(XmlFolderPath) Then Throw New Exception("Der Pfad zu den XML Dateien muss angegeben werden!")
    41. End Sub
    42. End Class
    43. End Namespace


    In jedem ViewModel kannst du nun jederzeit immer alle Daten laden und speichern. Musst aber nicht speichern. Du kannst z.b. auch das Property Rooms temporär auch bearbeiten und dann später speichern. Bleibt ganz dir überlassen. Die Klasse kann natürlich beliebig erweitert werden. Je nach belieben.

    PS: Hab die Klasse auch nicht getestet. Ist nur so runtergeschrieben.


    Grüße und gute Nacht
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Dazu nur kurz zwei Anmerkungen:
    Zur Vollständigkeit - auch wenn's wohl nix mit MultiUser werden soll: Instanziierung ggf. threadsicher machen (ab ca. 10:00)
    und
    manche Bedenken bzgl. Singleton (ab ca. 18:55 2:30) sollte man auch im Hinterkopf behalten, wenn man es verwendet.
    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.

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

    Danke für den Input. Ja, deshalb hatte ich extra gefragt ob Multiuser eine Option ist oder ob es nicht benötigt wird.

    Die einwende sind auch berechtigt, es gibt nicht viele Anwendungsfälle wo ich Singleton gut finde, aber in diesem Fall wo das Model recht klein ist und UnitTests, Mocks und der gleichen ziemlich unwarscheinlich sind denke ich das man damit gut aufgehoben ist.

    Es ist gerade wenn man mit ViewModels anfängt eine gute möglichkeit ohne gleich den ganzen Overhead mit dem weiterreichen von Instanzen zu haben.
    Aber der einwand ist natürlich berechtigt und gehört auch angesprochen, haste recht.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo,

    Nofear23m schrieb:

    Beispiel für eine Signleton-Klasse:

    Also ist das so eine Allgemeine Hilfsklasse mit auch noch anderen Funktionen (nicht nur für das laden und speichern) ?

    Warum macht es eigentlich Sinn, für jedes Property (Room, Device,...), das man laden und speichern kann eine eigene Methode anzulegen. Kann man doch alles in der LoadAllData() Methode machen. Ich sehe da gerade keinen Nutzen, welchen Hintergedanken hattest du?

    UnitTests und "Mocks" brauche ich nicht :)

    Viele Grüße
    Florian
    ----

    WebApps mit C#: Blazor

    flori2212 schrieb:

    welchen Hintergedanken hattest du?

    Einfach performance und "schönheit".

    Wenn du alle Räume neu einlesen möchtest dann ist es schlicht unnötig wieder ALLES neu einzulesen.
    Vorallem... könntest du so die List(Of Devices) bearbeitet haben und musst nicht daran denken alles zu speichern bevor du die Räume lädst. Denn wenn eine Methode ALLE Daten läd wäre die änderung in der Devicelist in dem Moment flöten gegangen.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Nofear23m

    Ja da hast du recht, ich denke manchmal einfach nicht so weit.

    Vielen Dank dir (und auch VaporiZed) für die Hilfe. :)

    Viele Grüße
    Florian
    ----

    WebApps mit C#: Blazor