giovedì 26 gennaio 2012
Stanchi della skin di default dell'emulatore di Windows Phone? Niente di più semplice: cambiatela! 
C'è un bellissimo progetto su CodePlex chiamato Windows Phone 7 Emulator Skin Switcher che vi permette di scegliere tra ben 25 skin diverse che riproducono l'estetica dei dispositivi più diffusi.
Io, ovviamente, ho ora la skin del Nokia Lumia 
Alessandro
Vi segnalo questo bellissimo post dell'amico Cristian Civera il quale ci spiega come applicare l'effetto di transizione che vediamo normalmente nella navigazione tra pagine in Windows Phone anche all'interno delle nostre app.
Cristian, secondo me, ha sempre avuto la grande dote di spiegare in modo semplice anche gli argomenti più complessi e questo post non è da meno.
Alessandro
Beth Massi ha pubblicato l'esempio completo, chiamato Address Book, a corredo della serie di post intitolata "Beginning Visual Studio LightSwitch", che potete trovare in questo suo post.
Nel citato post è anche disponibile l'elenco completo della serie di articoli che vi permetteranno di comprendere ancora meglio questo speciale ambiente di sviluppo.
Alessandro
giovedì 19 gennaio 2012
La piattaforma di sviluppo per Windows Phone mette a disposizione una serie di API per l'interazione con il Pictures Hub, che è poi il posto in cui vengono memorizzate le foto.
Una richiesta molto frequente è quella di poter salvare nel device foto da Internet, dato il loro indirizzo Web. Posto che ci siamo accertati di avere il permesso di poterlo fare
, ricorriamo a una serie di strumenti. Innanzitutto usiamo la classe WebClient per eseguire il download asincrono della foto. Quindi spostiamo il suo contenuto fatto di byte in un file all'interno dell'isolated storage, per poi eseguire il salvataggio vero e proprio.
Per interagire in modo rapido con l'hub delle foto è conveniente utilizzare la classe MediaLibrary (che non fa solo questo), messa a disposizione dall'assembly Microsoft.Xna.Framework. Tale assembly, al quale dobbiamo necessariamente aggiungere un riferimento nel nostro progetto, è specifico per i giochi sviluppati con XNA ma si integra perfettamente con le app.
Il codice che ci permette di eseguire questa operazione non è affatto complicato, richiede solo un po' di dimestichezza con gli stream. Eccolo, con i commenti che facilitano la lettura:
'The following Imports directives are required
'Imports System.Windows.Resources
'Imports System.IO
'Imports Microsoft.Xna.Framework.Media
'Imports System.IO.IsolatedStorage
Private Sub SavePictureToHub(webAddress As Uri, pictureName As String)
Dim client As New WebClient()
AddHandler client.OpenReadCompleted, Sub(sender As Object, e As OpenReadCompletedEventArgs)
'Get the result of the download operation as a stream
Dim resInfo As New StreamResourceInfo(e.Result, Nothing)
Dim reader As New StreamReader(resInfo.Stream)
'Get a reference to the isolated storage
Dim store = IsolatedStorageFile.GetUserStoreForApplication
'Read the downloaded stream
Dim contents As Byte()
Using bReader As New BinaryReader(reader.BaseStream)
contents = bReader.ReadBytes(CInt(reader.BaseStream.Length))
End Using
'Move the downloaded stream to a temp file into the isolated storage
Using fStream As IsolatedStorage.IsolatedStorageFileStream = store.CreateFile(pictureName)
fStream.Write(contents, 0, contents.Length)
End Using
'Save the picture to the Pictures hub (Saved pictures)
Using rStream As New IsolatedStorageFileStream(pictureName, FileMode.Open, store)
Dim ml As New MediaLibrary
ml.SavePicture(pictureName, rStream)
End Using
reader.Close()
'Remove the temp file from the isolated storage
store.DeleteFile(pictureName)
End Sub
client.OpenReadAsync(webAddress)
End Sub
Per una comodità personale uso le statement lambda dove posso, chiaramente si poteva incapsulare il codice della sub 'nidificata' in un delegate separato. L'unica cosa di cui tener conto (oltre, come detto, ad avere il permesso di scaricare la foto) è che le immagini verranno salvate nell'album chiamato Foto Salvate.
Alessandro
La tutela della privacy è importante in tanti contesti, ma forse in un dispositivo mobile lo è ancora di più. Non a caso, per l'invio di applicazioni al Marketplace di Windows Phone 7 per la certificazione, è necessario rispettare tutta una serie di policy.
Nello sviluppo per Windows Phone valgono ancora molti concetti relativi al namespace System.Security.Cryptography del .NET Framework, e proprio una tecnica già esistente ci permette di utilizzare un metodo semplificato per la protezione di informazioni, per così dire, meno delicate.
Esiste infatti la classe ProtectedData che espone due metodi condivisi, Protect e Unprotect. Il primo riceve una stringa e la restituisce sotto forma di array di byte sotto encryption. Il secondo, ovviamente, vuole l'array di byte e restituisce la stringa originaria.
Ciò premesso, vediamo come definire una classe che faccia uso di questa tecnica:
Imports System.Security.Cryptography
Imports System.Text
Public Class CryptoService
Public Shared Function EncryptString(data As String) As Byte()
Dim PinByte = Encoding.UTF8.GetBytes(data)
Dim ProtectedPinByte = ProtectedData.Protect(PinByte, Nothing)
Return ProtectedPinByte
End Function
Public Shared Function DecryptData(data As Byte()) As String
Dim unprotected = ProtectedData.Unprotect(data, Nothing)
Return Encoding.UTF8.GetString(unprotected, 0, unprotected.Length)
End Function
End Class
Il primo metodo, chiamato EncryptString, converte dapprima la stringa in array di byte e poi la protegge con il metodo ProtectedData.Protect. Viceversa, il secondo metodo, chiamato DecryptData, ottiene l'array di byte non protetto e ne restituisce la stringa corrispondente. L'utilizzo di questa tecnica va poi abbinato all'uso degli stream e dell'isolated storage del dispositivo. Il seguente codice dimostra come leggere informazioni protette e come elaborarle:
Dim store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication
Using protStream As New IsolatedStorageFileStream("miofile.bin", IO.FileMode.Open, store)
Dim pinArray As Byte() = New Byte(CInt(protStream.Length - 1)) {}
protStream.Read(pinArray, 0, pinArray.Length)
info = CryptoService.DecryptData(pinArray)
End Using
Dove info è una variabile di tipo stringa dichiarata altrove. Il seguente codice, invece, scrive in un file il contenuto di una stringa proteggendolo:
Using protStream As New IsolatedStorageFileStream("miofile.bin", IO.FileMode.Create, store)
Dim dati = "info delicatissime"
Dim datiProtetti = CryptoService.EncryptString(dati)
protStream.Write(datiProtetti, 0, datiProtetti.Length)
End Using
A seconda del tipo di informazioni da proteggere può essere conveniente utilizzare altre tecniche, questa comunque è molto semplice e certamente efficace all'interno delle nostre app. Un'occhiata a MSDN per concludere.
Alessandro
martedì 17 gennaio 2012
Spesso capita l'esigenza di eseguire un ciclo For..Each su entity set lavorando con ADO.NET Entity Framework. Qualcosa tipo:
For Each animal In MyModel.Animals
'Do something here...
Next
Nell'esempio di cui sopra l'entity set Animals è di tipo ObjectSet(Of T), dove chiaramente T è un tipo fittizio Animal. Nel ciclare direttamente un oggetto di tipo ObjectSet(Of T) l'EF potrebbe restituire la seguente eccezione:
"New transaction is not allowed because there are other threads running in the session". Per risolvere il problema è necessario evitare di ciclare direttamente contro l'ObjectSet, il che vuol dire poter usare anche un metodo extension come AsQueryable o ToList:
For Each animal In MyModel.Animals.AsQueryable()
Next
In questo modo sarà possibile eseguire correttamente il ciclo evitando l'errore, ovviamente potrebbe essere preferibile scrivere una query LINQ piuttosto che usare direttamente gli extension, a seconda del contesto.
Alessandro
Venerdì 27 gennaio p.v. sarò a Genova con gli amici di DotNetLiguria, giovane user group con focus sulle tecnologie .NET che si propone di aggregare utenti e appassionati liguri.
Raf e i suoi ragazzi hanno infatti organizzato il 1° workshop del 2012 e in questo ambito presenterò, alle ore 18, una sessione su Visual Studio LightSwitch, sarà una sessione di livello introduttivo ma tarata per sviluppatori non troppo principianti 
Ci sarà anche una interessante round-table sul futuro di Silverlight e una sessione sui code contracts. Se siete in zona ligure e non avete impegni venite a trovarci, potete trovare i dettagli sull'evento nell'home page di DotNetLiguria mentre potete registrarvi seguendo questo link.
Vi aspettiamo!
Alessandro
mercoledì 11 gennaio 2012
In un'app che sto sviluppando per Windows Phone 7.5 avevo la necessità di integrare un elenco di video proveniente da uno specifico canale di YouTube, visualizzando tale elenco in una ListBox e permettendo la riproduzione del video selezionato dall'utente.
Non avendolo mai fatto e cercando un po', mi sono imbattuto in questo interessante articolo su Visual Studio Magazine che mi ha messo sulla strada giusta e che, ovviamente, ho riadattato alle mie esigenze (non ultimo il passaggio del codice a Visual Basic
).
La prima cosa da fare è determinare l'indirizzo Web del feed contenente l'elenco dei video desiderati. Ci sono URL diversi a seconda del fatto che si voglia interrogare un canale o una categoria. In questo esempio mostrerò come interrogare un canale, che poi si traduce nell'interrogare tutti i video caricati da uno specifico utente.
YouTube mette a disposizione delle specifiche API per fare questo, atteso che i feed RSS non sono più disponibili come una volta. La developer guide di YouTube è disponibile qui.
Supponiamo di voler elencare tutti i video nel canale YouTube dei Queen, ma la mia rock band preferita. Il feed per questo elenco è così conformato:
http://gdata.youtube.com/feeds/api/users/queenofficial/uploads?orderby=updated
Potete banalmente verificarlo digitando il link nel vostro browser. Come fare ora per utilizzarlo in Windows Phone? Innanzitutto ci vuole un DataTemplate per la ListBox che utilizzeremo. In questo template decidiamo di mostrare la thumbnail del video e la descrizione:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="SearchResultsItemTemplate">
<StackPanel Margin="0,0,0,30" Orientation="Horizontal">
<Image Source="{Binding VideoImageUrl}" HorizontalAlignment="Left" Width="100"
Height="90" Stretch="UniformToFill" VerticalAlignment="Top"/>
<TextBlock Text="{Binding Title}" VerticalAlignment="Top" Width="300"
HorizontalAlignment="Left" Margin="10,0,0,0" TextWrapping="Wrap"/>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Successivamente ci vuole la ListBox... molto semplice:
<ListBox x:Name="ResultsList"
ItemTemplate="{StaticResource SearchResultsItemTemplate}"
ItemsSource="{Binding}" SelectionChanged="VideoListSelectionChanged" />
Come vedete viene specificato il template per gli elementi. Ora ci sono tre cose da fare. La prima è definire una classe che rappresenti un video. In forma semplificata, per le informazioni che servono a noi, questo può essere un esempio:
Public Class YouTubeVideo
Public Property Title As String
Public Property VideoImageUrl As String
Public Property VideoId As String
End Class
La seconda cosa da fare è stabilire il caricamento dell'elenco dei video. Il posto all'interno dell'applicazione varia a seconda delle vostre esigenze, diciamo che il frammento di codice necessario è, a livello generale, simile al seguente:
Dim w As New WebClient
AddHandler w.DownloadStringCompleted, Sub(sender As Object, e As DownloadStringCompletedEventArgs)
Dim atomns = XNamespace.Get("http://www.w3.org/2005/Atom")
Dim medians = XNamespace.Get("http://search.yahoo.com/mrss/")
Dim xml = XElement.Parse(e.Result)
Dim videos = (From entry In xml.Descendants(atomns.GetName("entry"))
Select New YouTubeVideo With {.VideoId = entry.Element(atomns.GetName("id")).Value,
.VideoImageUrl = (From thumbnail In entry.Descendants(medians.GetName("thumbnail"))
Where thumbnail.Attribute("height").Value = "90"
Select thumbnail.Attribute("url").Value).FirstOrDefault(),
.Title = entry.Element(atomns.GetName("content")).Value}).ToArray()
ResultsList.ItemsSource = videos
searchUri = "http://gdata.youtube.com/feeds/api/users/queenofficial/uploads?orderby=updated"
w.DownloadStringAsync(New Uri(searchUri))
Il feed RSS è sempre un contenuto XML, di conseguenza usiamo LINQ to XML per analizzare il contenuto del feed e per creare un'istanza della classe YouTubeVideo, popolandola con le relative proprietà, per ciascun elemento nel feed. Non ho utilizzato gli XML Literals di VB in questo caso per due ragioni: la prima è che dobbiamo fare riferimento a un namespace diverso nei descendants e la seconda è che tanto lo so che anche chi usa C# capita di qua 
Fatto questo l'ultimo step è gestire l'evento changed sulla selezione nella ListBox. Ecco il codice:
Private Sub VideoListSelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
Dim video = CType(ResultsList.SelectedItem, YouTubeVideo)
If video IsNot Nothing Then
Dim parsed = video.VideoId.Split(CChar("/"))
Dim id = parsed(parsed.Length - 1)
Dim playbackUrl = "vnd.youtube:" + id
Dim task As New WebBrowserTask With {.Uri = New Uri(playbackUrl)}
task.Show()
End If
End Sub
In sostanza l'elemento selezionato viene convertito in un'istanza della classe YouTubeVideo della quale vengono lette le proprietà e con queste viene costruito l'URL del video, che viene avviato tramite il launcher WebBrowserTask.
A questo punto entra in gioco quello che secondo me è l'unico neo di questa tecnica: per riprodurre il video è necessario avere sul device l'app per YouTube, che è quella gratuita di Microsoft. Neo nel senso che la riproduzione avverrà, a causa del formato di video, tramite un'app esterna che comunque rimane gratuita e comunque, se non disponibile, sarà il dispositivo a suggerire all'utente di installarla. Questo ha anche un'implicazione: l'emulatore non permette il download dal Market Place, di conseguenza sarete in grado di visualizzare l'elenco ma per riprodurre un video dovrete fare il test sul device fisico.
Nonostante queste piccolezze, si tratta di una tecnica molto efficace soprattutto se dovete visualizzare video che non avete in altro formato ma che sapete siano disponibili su YouTube.
Alessandro