2017-06-01 1 views
0

Ich habe Fragen zur Serialisierung und Deserialisierung von ViewModels - Ich erstelle eine Instanz des ViewModel und weise sie dem DataContext einer View zu. Ich habe eine Liste mit Objekten im ViewModel, die ich serialisieren und dann deserialisieren muss.Serialisierung und Deserialisierung des Ansichtsmodells

Beim Deserialisieren wächst die Größe der Liste, nicht sicher, was hier passiert. Ist ein ViewModel nicht einfach eine weitere Instanz einer Klasse?

Zum Beispiel fange ich mit 2 Objekten einer Klasse an. Ich serialisiere und deserialiere es, und ich habe 4 Datensätze, die Größe wächst weiter.

Ich habe ein Stück Testszenario dafür gemacht. Ich benutze JSON Serializer.

// --- Ansicht Modell --- //

using System; 
using System.Windows; 
using System.Windows.Input; 
using Newtonsoft.Json; 

namespace JsonTest 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     CarVM = new CarViewModel(); //Create instance if View Model and assign it to the datacontext 
     this.DataContext = CarVM; 

    } 

    private CarViewModel CarVM { get; set; } 


    /// <summary> 
    /// Serialize 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    private void Serialize_Click(object sender, RoutedEventArgs e) 
    { 
     //Serialize and write to file 
     using (var fileStream = new FileStream(@"Config123.cfg", FileMode.Create)) 
     using (var streamWriter = new StreamWriter(fileStream)) 
     using (var jsonWriter = new JsonTextWriter(streamWriter)) 
     { 
      JsonSerializer ser = new JsonSerializer(); 
      ser.Formatting = Newtonsoft.Json.Formatting.Indented; //Format the output 
      ser.TypeNameHandling = TypeNameHandling.Auto; 
      ser.Serialize(jsonWriter, CarVM); //Serailizing View Model objects 
      jsonWriter.Flush(); 
     } 

     printData(); 
    } 

    /// <summary> 
    /// Deserialize 
    /// </summary> 
    /// <param name="sender"></param> 
    /// <param name="e"></param> 
    private void Deserialize_Click(object sender, RoutedEventArgs e) 
    { 
     using (var fileStream = new FileStream(@"Config123.cfg", FileMode.Open)) 
     using (var streamReader = new StreamReader(fileStream)) 
     using (var jsonReader = new JsonTextReader(streamReader)) 
     { 
      JsonSerializer ser = new JsonSerializer(); 
      ser.Formatting = Newtonsoft.Json.Formatting.Indented; 
      ser.TypeNameHandling = TypeNameHandling.Auto; 
      CarVM = ser.Deserialize<CarViewModel>(jsonReader); //reload the ViewModel with new viewmodel obtained from serializing 
     } 
     Console.WriteLine("--Deserialization--"); 
     printData(); 
    } 

    /// <summary> 
    /// Print Data 
    /// </summary> 
    private void printData() 
    { 
     foreach(Car c in CarVM.Cars) 
     { 
      Console.WriteLine(c.make + " " + c.year); 
     } 
    } 
    } 
} 

// --- Einfach Klasse --- //

namespace JsonTest 
{ 
class Car 
{ 
    public string make { get; set; } 
    public int year { get; set; } 

    public Car() { } 

    public Car(string make, int year) 
    { 
     this.make = make; 
     this.year = year; 
    } 
    } 
} 

// --- Die View- - //

<Window x:Class="JsonTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:JsonTest" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <Button Content="Serialize" Margin="50" BorderThickness="0" Click="Serialize_Click"/> 
     <Button Grid.Column="1" Content="Deserialize" Margin="50" BorderThickness="0" Click="Deserialize_Click"/> 
    </Grid> 
</Window> 

// --- Ausgang --- //

--Serialization-- 
DeLorean 1975 
Subaru 2018 
--Deserialization-- 
DeLorean 1975 
Subaru 2018 
DeLorean 1975 
Subaru 2018 
--Serialization-- 
DeLorean 1975 
Subaru 2018 
DeLorean 1975 
Subaru 2018 
--Deserialization-- 
DeLorean 1975 
Subaru 2018 
DeLorean 1975 
Subaru 2018 
DeLorean 1975 
Subaru 2018 
// 210

--- CarViewModel --- //

class CarViewModel 
    { 
     public CarViewModel() 
     { 
      Cars = new List<Car>(); 
      Cars.Add(new Car("DeLorean", 1975)); 
      Cars.Add(new Car("Subaru", 2018)); 
     } 

     private List<Car> cars; 
     public List<Car> Cars 
     { 
      get { return cars; } 
      set { cars = value; } 
     } 
    } 
+0

Vielleicht 'CarVM.Cars' verwendet ein statisches Hintergrundfeld. Da 'CarsViewModel' das von Ihnen gewünschte Verhalten aufweist, sollten Sie diesen Code mit anderen teilen. –

+0

@Ed - Nur mit ViewModel-Code aktualisiert. –

Antwort

2

Im Viewmodel Konstruktor, fügen Sie zwei Autos.

public CarViewModel() 
    { 
     Cars = new List<Car>(); 
     Cars.Add(new Car("DeLorean", 1975)); 
     Cars.Add(new Car("Subaru", 2018)); 
    } 

Wenn Sie serialisieren, serialisiert es beide Autos.

Beim Deserialisieren erstellt der Deserializer eine Instanz Ihrer Klasse mit dem Standardkonstruktor. Der Standardkonstruktor fügt diese beiden Autos hinzu. Dann fügt der Deserializer die beiden Autos hinzu, die im JSON serialisiert wurden.

Dies ist nicht das Verhalten, das Sie im Sinn hatten. Fügen Sie keine Testdaten in Ihren Viewmodel-Konstruktor ein, wenn Sie Serialisierung und Deserialisierung durchführen möchten.

public CarViewModel() 
{ 
    Cars = new List<Car>(); 
} 

es hier hinzufügen - einmalig:

public MainWindow() 
{ 
    InitializeComponent(); 
    CarVM = new CarViewModel 
    { 
     Cars = { 
      new Car("DeLorean", 1975), 
      new Car("Subaru", 2018) 
     }; 
    } 

    this.DataContext = CarVM; 
} 

Auch nicht verwenden List<T> für ein Ansichtsmodell. Verwenden Sie ObservableCollection<T>. Beim Hinzufügen oder Entfernen von Elementen werden alle gebundenen Sammlungssteuerelemente in der Benutzeroberfläche benachrichtigt. Sie sollten auch INotifyPropertyChanged in Ihrem Ansichtsmodell implementieren, damit Änderungen an den Eigenschaften auch dazu führen, dass die Benutzeroberfläche benachrichtigt wird.

+0

Danke für die Antwort und die Erklärung. Macht jetzt Sinn. Ich verwende 'ObservableCollection ' und 'INotifyPropertychanged' im tatsächlichen ViewModel Code, ein bisschen komplexer. Ich habe es jedoch nicht für das Testszenario verwendet. Vielen Dank. –

+0

@SanMor Klingt gut. –

Verwandte Themen