venerdì 18 maggio 2012

Metro Style Apps – I samples di MSDN e il SuspensionManager

Chi si avvicina al mondo delle Metro Style Apps in questo momento, probabilmente, fa uso smodato dei samples che si trovano al link:

http://code.msdn.microsoft.com/windowsapps/

Coloro che scaricano i samples in VB (ma mi sembra ci sia anche in C#), troveranno un interessante modulo per gestire i dati da salvare su isolated storage per la gestione, ad esempio, della sospensione.

Tale modulo si chiama SuspensionManager e utilizza un Dictionary(Of String, Object) per la memorizzazione dei dati da salvare in sessione.

Sono presenti, poi, due metodi per salvare e recupere il dictionary dall'isolated storage i quali utilizzano un DataContractSerializer per la serializzazione.

Per semplicità riporto il modulo presente nei samples:

  1. ' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. ' ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. ' THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. ' PARTICULAR PURPOSE.
  5. '
  6. ' Copyright (c) Microsoft Corporation. All rights reserved
  7.  
  8. Imports System.IO
  9. Imports System.Runtime.Serialization
  10. Imports Windows.Storage
  11. Imports Windows.Storage.Streams
  12.  
  13. Module SuspensionManager
  14.     Private sessionState_ As New Dictionary(Of String, Object)
  15.     Private knownTypes_ As List(Of Type) = New List(Of Type)
  16.     Private Const filename As String = "_sessionState.xml"
  17.  
  18.     ' Provides access to the currect session state
  19.     Public ReadOnly Property SessionState As Dictionary(Of String, Object)
  20.         Get
  21.             Return sessionState_
  22.         End Get
  23.     End Property
  24.  
  25.     ' Allows custom types to be added to the list of types that can be serialized
  26.     Public ReadOnly Property KnownTypes As List(Of Type)
  27.         Get
  28.             Return knownTypes_
  29.         End Get
  30.     End Property
  31.  
  32.     ' Save the current session state
  33.     Public Async Function SaveAsync() As Task
  34.         ' Get the output stream for the SessionState file.
  35.         Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
  36.         Dim raStream As IRandomAccessStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
  37.         Using outStream As IOutputStream = raStream.GetOutputStreamAt(0)
  38.             ' Serialize the Session State.
  39.             Dim serializer As New DataContractSerializer(GetType(Dictionary(Of String, Object)))
  40.             serializer.WriteObject(outStream.AsStreamForWrite, sessionState_)
  41.             Await outStream.FlushAsync
  42.         End Using
  43.     End Function
  44.  
  45.     ' Restore the saved sesison state
  46.     Public Async Function RestoreAsync() As Task
  47.         ' Get the input stream for the SessionState file.
  48.         Try
  49.             Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.GetFileAsync(filename)
  50.             If file Is Nothing Then
  51.                 Exit Function
  52.             End If
  53.             Dim inStream As IInputStream = Await file.OpenSequentialReadAsync
  54.  
  55.             ' Deserialize the Session State.
  56.             Dim serializer As New DataContractSerializer(GetType(Dictionary(Of String, Object)))
  57.             sessionState_ = CType(serializer.ReadObject(inStream.AsStreamForRead), Dictionary(Of String, Object))
  58.         Catch ex As Exception
  59.             ' Restoring state is best-effort.  If it fails, the app will just come up with a new session.
  60.         End Try
  61.     End Function
  62.  
  63. End Module

A parte che, personalmente (ma è gusto personale, quindi opinabile), non amo i moduli vecchio stile, il modulo proposto negli esempi non permette di serializzare eventuali nostre classi.

Questo perchè è previsto l’attributo privato knownTypes_ di tipo List(Of Type) (con relativa properietà esposta) ma, di fatto, non ne viene fatto uso nel DataContractSerializer:

  1. ' Get the output stream for the SessionState file.
  2. Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
  3. Dim raStream As IRandomAccessStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
  4. Using outStream As IOutputStream = raStream.GetOutputStreamAt(0)
  5.     ' Serialize the Session State.
  6.     Dim serializer As New DataContractSerializer(GetType(Dictionary(Of String, Object)))
  7.     serializer.WriteObject(outStream.AsStreamForWrite, sessionState_)
  8.     Await outStream.FlushAsync
  9. End Using

La modifica da apportare, quindi, per gestire le nostre classi (ovviamente purchè le stesse siano serializzabili) è di comunicare al DataContractSerializer che abbiamo dei tipi che deve conoscere:

  1. ' Get the output stream for the SessionState file.
  2. Dim file As StorageFile = Await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting)
  3. Dim raStream As IRandomAccessStream = Await file.OpenAsync(FileAccessMode.ReadWrite)
  4. Using outStream As IOutputStream = raStream.GetOutputStreamAt(0)
  5.     ' Serialize the Session State.
  6.     Dim serializer As New DataContractSerializer(GetType(Dictionary(Of String, Object)), knownTypes_)
  7.     serializer.WriteObject(outStream.AsStreamForWrite, sessionState_)
  8.     Await outStream.FlushAsync
  9. End Using

Per poter, dunque, utilizzare liberamente le nostre classi potremmo, una tantum, aggiungere i nostri tipi ed essere sicuri che il tutto funzioni:

  1. SuspensionManager.Instance.KnownTypes.Add(GetType(Contact))

In allegato al post trovate la solution per Visual Studio 11 Beta con la classe e una modesta interfaccia di prova.

 

 

Nessun commento: