Molto spesso le nostre app per Windows 8 hanno la necessità di memorizzare informazioni su disco in fase di chiusura o sospensione, e poterle recuperare in fase di avvio o resume. Windows 8 non ha l'Isolated Storage, per cui ci viene suggerito di usare il namespace Windows.Storage per la gestione di file locali. Questo comporta l'utilizzo di tecniche di serializzazione.
Ci sono diverse metodologie, oggi ne vediamo una piuttosto semplice. Supponiamo di avere una classe che rappresenti un qualcosa e che la nostra app debba memorizzare una collection di oggetti di questo tipo. La classe:
Imports System.Runtime.Serialization
<DataContract> Public Class MyItem
<DataMember> Public Property MyStuff As String
<DataMember> Public Property MyCounter As Integer
End Class
Al di là del significato puramente dimostrativo della classe, focalizziamo l'attenzione sul fatto che sia marcata come DataContract e le sue proprietà come DataMember, sfruttando attributi del namespace System.Runtime.Serialization. Questo è richiesto per far si che l'oggetto sia serializzabile.
Ora vediamo come salvare su disco un file locale contenente una ObservableCollection(Of MyItem):
Shared Async Function CreateDataFileAsync(theData As ObservableCollection(Of MyItem)) As Task
Try
Dim file = Await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync("MyData.bin",
Windows.Storage.CreationCollisionOption.ReplaceExisting)
Dim write = Await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)
Using write.GetOutputStreamAt(0)
Dim serializer As New DataContractSerializer(GetType(ObservableCollection(Of MyItem)))
serializer.WriteObject(write.AsStreamForWrite, theData)
End Using
Catch ex As Exception
End Try
End Function
La classe ApplicationData rappresenta l'insieme di dati che fanno capo all'app, la sua proprietà Current rappresenta l'istanza attiva dell'app, LocalFolder rappresenta la cartella locale dell'applicazione, il metodo CreateFileAsync crea il file specificato in modalità asincrona (da qui l'utilizzo con Await) mentre l'enum CreationCollisionOption permette di stabilire se il file debba essere sovrascritto se esistente (ReplaceExisting), aperto se esistente (OpenIfExists), generato con nome univoco (GenerateUniqueName) o se debba essere sollevata un'eccezione (FailIfExists). Il risultato è un tipo Windows.Storage.StorageFile, il cui metodo OpenAsync permette l'apertura del file come stream. Attraverso un'istanza della classe DataContractSerializer si ottiene un oggetto serializzabile all'interno di uno stream il cui punto di ingresso è ottenuto attraverso il metodo GetOutputStreamAt. Infine, l'oggetto viene scritto attraverso il metodo DataContractSerializer.WriteObject, che necessita di una conversione in stream per scrittura dell'oggetto StorageFile ottenuto precedentemente.
La lettura del file avviene in modo abbastanza simile:
Shared Async Function ReadDataFileAsync() As Task(Of ObservableCollection(Of MyItem))
Try
Dim file = Await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync("MyData.bin")
Dim theData As ObservableCollection(Of MyItem)
If file IsNot Nothing Then
Using session = Await file.OpenAsync(Windows.Storage.FileAccessMode.Read)
Dim serializer As New DataContractSerializer(GetType(ObservableCollection(Of MyItem)))
Dim data = serializer.ReadObject(session.AsStreamForRead)
theData = CType(data, ObservableCollection(Of MyItem))
End Using
Return theData
Else
Return Nothing
End If
Catch ex As Exception
Return Nothing
End Try
End Function
Differenze principali: l'utilizzo di GetFileAsync per aprire il file in lettura, del metodo DataContractSerializer.ReadObject per deserializzare l'oggetto e la conversione dello StorageFile in stream per lettura. I dati deserializzati vengono convertiti nel tipo appropriato e restituiti al chiamante.
Un esempio d'uso:
Await CreateDataFileAsync(MyCollection)
I vari template di progetto per Windows 8 che includono la classe SuspensionManager, offrono ulteriori esempi di serializzazione, dimostrando come persistere e ripristinare lo stato dell'app. Quindi, vi consiglio di consultare anche quel codice.
Alessandro