Search code examples
vb.netserializationuwpjson.netwindows-community-toolkit

How to serialize a List(of Object) in VB.NET?


I have a class Player that I use to create a List(Of Player). I need to save it when the application closes. In Windows Forms, I would just serialize, but that's no longer possible in UWP, so I had to Google for a few dozen of hours and I finally stumbled upon Microsoft.Toolkit.Uwp, then Newtonsoft.Json, but I fail miserably to use them. I need your help!

Let's say I have a small class :

Dim Name As String
Dim Score As Double
Public Class Player
    <JsonConstructor()>
    Public Sub New(Name As String, Score As Double) ' New with score
        Me.Name = Name
        Me.Score = Math.Max(1, Score)
    End Sub
End Class
Public Overrides Function ToString() As String ' ToString
    Return $"{Name} [{Score}]"
End Function

How do I successfully read and write a List(Of Player)?

' Loading MainPage.xaml
Private Sub MainPage_Loading() Handles Me.Loading
    ReadAsync()
    MainFrame.Margin = New Thickness(0)
    Window.Current.Content = MainFrame
    MainFrame.Navigate(GetType(PlayerList), Players)
End Sub

' Read
Private Async Sub ReadAsync()
    Players = JsonConvert.DeserializeObject(Of List(Of Player))(Await FileIO.ReadTextAsync((Await StorageFolder.CreateFileAsync("players.json", CreationCollisionOption.OpenIfExists))))
    If Players Is Nothing Then
        Players = New List(Of Player)
        WriteAsync()
    End If
End Sub

' Write
Public Shared Async Sub WriteAsync()
    Await FileIO.WriteTextAsync(Await StorageFolder.CreateFileAsync("players.json", CreationCollisionOption.ReplaceExisting), JsonConvert.SerializeObject(Players, Formatting.Indented))
End Sub

' Loading PlayerList.xaml
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
    ListBoxPlayers.Items.Clear()
    Players = e.Parameter
    For Each Player In Players
        ListBoxPlayers.Items.Add(Player)
    Next
End Sub

' Adding a new player in the interface
Private Sub ButtonAddPlayer_Click(sender As Button, e As RoutedEventArgs) Handles ButtonAddPlayer.Click
    ' ...
    ' Commit
    MainPage.Players.Add(New Player(TextBoxName.Text))
    ListBoxPlayers.Items.Add(MainPage.Players(MainPage.Players.Count - 1))
    MainPage.WriteAsync()
End Sub

So this is all confusing. When I add a player trough the interface, it enters my ListBox like normal. However, when I close the application and I re-open it, I get a handful of empty objects.

List of different players Serialization didn't work!

I did some angry testing to know more about my problem, turns out I'm not serializing at all, but I probably am deserializing correctly.

Angry testing


Solution

  • I found it, turns out it's in my class Player.

    What I used :

    Dim Name As String
    Dim Score As Double
    

    What worked :

    Public Name As String
    Public Score As Double
    

    What I should have done :

    Public Property Name As String
    Public Property Score As Double
    

    I was taught to never set variables as "public" when coding in Java, and I didn't know that Property existed in Visual Basic.