Any programmer will tell you that serialization is quite tricky in any circumstances. Add to the trickiness of serialization the fact that you have to serialize a Windows Store app, then you have double the trickiness! Today I will show you how to properly serialize Windows Store apps. Let's jump in.
In case you do not know what serialization is, here is a small breakdown: Serialization is storing and retrieving data. This can be small pieces of information you need to save and retrieve, or large amounts of data. The choice of serialization ultimately depends on the amounts of data you need to save. Once the choice has been made, you need to realize what you're working with. This may sound strange, but you have to remember that Windows Store apps differ very much from desktop apps, and that you cannot implement the same logic into them as you'd have done with Desktop apps.
We cannot choose where we want to save small bits of info, it's done automatically. The only choice we have is to have the information always available or not. With today's example we will create a Windows Store app that stores a class object, and then reads the information stored back into our application. Let's create our project. Open up Visual Studio 2013 and choose to create a Windows Store app with Visual Basic. Design your main page as displayed in Figure 1.
Figure 1 - Our design
Your MainPage.xaml code should contain the following:
<Button x:Name="btWrite" Content="Write" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="148,94,0,0" Grid.Row="1"/> <Button x:Name="btRead" Content="Read" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="316,94,0,0" Grid.Row="1"/> <ListBox x:Name="ltStudents" HorizontalAlignment="Left" Height="187" VerticalAlignment="Top" Width="312" Margin="476,94,0,0" Grid.Row="1"/> <ListBox x:Name="ltCourses" HorizontalAlignment="Left" Height="187" VerticalAlignment="Top" Width="250" Margin="804,94,0,0" Grid.Row="1"/>
The first issue to address is: What do we want to store? In our example we will have to store a student object and then later retrieve the info we have stored. We need to create a class called Student and give this class some properties. We will use the values of these properties our project to save and read. Let's add the Student class now by selecting Project, Add New Item, Class and give the name Student. Add the following code to it:
'Class To Be Serialized Public Class Student Private StuName As String 'Name Private StuCourse As String 'Course 'StudentName Property Public Property StudentName As String Get Return StuName End Get Set(value As String) StuName = value End Set End Property 'StudentCourse Property Public Property StudentCourse As String Get Return StuCourse End Get Set(value As String) StuCourse = value End Set End Property End Class
The Student class has only two properties: StudentName and StudentCourse. We will populate these properties with data, then save it to a file. Lastly, we will read this saved data back into the program. Let's move on to the MainPage's code. Add the next Import statements for all the necessary namespaces we need to include in our app to be able to write and read files:
Imports System.Runtime.Serialization Imports Windows.Storage Imports System.Xml.Serialization Imports Windows.Storage.Streams
These classes facilitate working with data and files.
Now, let us add the needed code in order to write the student class' properties to a file.
Private Async Function WriteStudentInfo(Of T)(stuData As T, xmlFile As StorageFile) _ As Task 'Function To Store Student Object Try 'In Case Anything Goes Wrong Dim swStudent As New StringWriter() 'Create New StringWriter Object Dim raRoot As New XmlRootAttribute("StudentsExample") 'Root Element raRoot.IsNullable = True 'Can Be Null Dim xmlStudent As New XmlSerializer(GetType(T), raRoot) 'Write What? xmlStudent.Serialize(swStudent, stuData) 'Serialize Student Object Using fsStudent As IRandomAccessStream = _ Await xmlFile.OpenAsync(FileAccessMode.ReadWrite) 'Start Write Process Using fiosStudentOutput As IOutputStream = fsStudent.GetOutputStreamAt(0) 'Get Output Start Using dwStudent As New DataWriter(fiosStudentOutput) dwStudent.WriteString(swStudent.ToString()) 'Write Student Info Object Await dwStudent.StoreAsync() dwStudent.DetachStream() 'Close File End Using Await fiosStudentOutput.FlushAsync() 'Flush All That Needs To Be Written End Using End Using Catch e As Exception Throw New NotImplementedException(e.Message.ToString()) 'Error End Try End Function Private Async Sub btWrite_Click(sender As Object, e As RoutedEventArgs) Handles btWrite.Click Dim stu As New Student 'Create Student Object To Store 'Initialize Values stu.StudentName = "Hannes" stu.StudentCourse = "Computer Literacy" 'Create The File Dim sfStudent As StorageFile = _ Await ApplicationData.Current.LocalFolder.CreateFileAsync("data.xml", _ CreationCollisionOption.ReplaceExisting) Await WriteStudentInfo(stu, sfStudent) 'Write Info End Sub
Here in our WriteSudentInfo Function, we make use of the XMLSerializer class to save the needed info. That's not all. We needed to create the file ( if it didn't exist ) and then write the contents of our Student class through the use of the DataWriter class. With the button click, we simply populated the Student class' properties and called the WriteStudentInfo function to start the write process.
The file that is created and written to is named: data.xml and is stored at a location similar to C:\Users\UserName\AppData\Local\Packages\UniqueIdentifierNumber\LocalState, as displayed in Figure 2.
Figure 2 - The data.xml file
The contents of the data.xml file looks like:
<?xml version="1.0" encoding="utf-16"?> <Student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <StudentName>Hannes</StudentName> <StudentCourse>Computer Literacy</StudentCourse> </Student>
Add the following code to read the data back into our program:
Private Async Function ReadStudentInfo(xmlFile As StorageFile) As Task(Of Student) 'Function To Read Student Info Stored Dim raRoot As New XmlRootAttribute("StudentsExample") 'Root Element Dim xmlStudent As New XmlSerializer(GetType(Student), raRoot) 'Read What? Dim stuData As Student 'Final Student Object Dim objStudent As New Object 'Student Object Read Using strmStudent = Await xmlFile.OpenStreamForReadAsync() 'Open XML File For Reading Dim txtReader As TextReader = New StreamReader(strmStudent) 'Read Info objStudent = xmlStudent.Deserialize(txtReader) 'Get Info stuData = DirectCast(objStudent, Student) 'Cast To Student End Using Return stuData 'Return Student Object End Function Private Async Sub btRead_Click(sender As Object, e As RoutedEventArgs) Handles btRead.Click Dim stu As Student 'Create Student Object 'Make Sure File Exists Dim sfStudent As StorageFile = Await ApplicationData.Current.LocalFolder.GetFileAsync("data.xml") stu = Await ReadStudentInfo(sfStudent) 'Read Info Into stu 'Show Values ltStudents.Items.Add(stu.StudentName) ltCourses.Items.Add(stu.StudentCourse) End Sub
Inside the ReadStudentInfo Function, we read the info stored inside the data.xml file and deserialize it. We then simply display the file's contents inside our two listboxes.
Once run, and the Read button is clicked you will see a screen similar to Figure 3.
Figure 3 - Our working program
There are numerous ways to save info, XML Serialization just being one of the most useful of the lot. In my next article you will see what we can do without registry access in a Windows Store app. Until then, cheers!