In questa guida abbiamo già esaminato le principali novità di Windows RT in tema di user experience. In particolare, abbiamo visto come le classiche icone del desktop abbiano lasciato il posto a tile animate e personalizzate, e abbiamo accennato al modo con cui differenti tile applicative devono essere referenziati nell'application manifest della nostra applicazione.
Nell'immagine seguente c'è una Start Page di Windows RT, con una varietà di tile animate e dinamiche, alcune più grandi e di forma rettangolare ("wide
"), altre più piccole e quadrate ("square
"). Le tile permettono di fornire informazioni all'utente (o semplicemente di stimolarne la curiosità e attrarne l'attenzione, come nel caso dell'applicazione nativa Travel) anche quando l'applicazione non è in esecuzione.
Alcune di esse presentano solo delle immagini (è il caso, ad esempio, dell'applicazione custom "Learn With The Animals"), altre del semplice testo o, più spesso, una combinazione di testo e immagini (l'applicazione News, ad esempio, mostra il titolo delle notizie più importanti, accompagnato dalla corrispondente foto, mentre l'applicazione Travel alterna immagini e testo).
Alcune tile mostrano anche un ulteriore elemento informativo nell'angolo inferiore destro, ossia un "badge". Un badge può essere utilizzato per mostrare un numero (da 1 a 99), oppure un particolare simbolo (denominato "status glyph") per rappresentare un determinato stato applicativo.
Ad esempio, la tile dell'applicazione nativa Mail, mostrata nella prossima immagine in alto a sinistra, usa un badge numerico per indicare il numero di email non lette, mentre nel corpo del tile è mostrato un breve estratto di queste.
Ciò premesso, in questo articolo ci occuperemo di come gestire, animare e modificare tile e badge delle nostre applicazioni Windows Store.
Per prima cosa, apriamo Visual Studio 2012 e creiamo un nuovo progetto Windows Store, come mostrato nella prossima immagine:
Prima di procedere oltre, però, ci servono alcune immagini da utilizzare per il tile "square" (Logo.png
) e per quello "wide" (LogoWide.png
), nonché un po' di dati d'esempio da mostrare a video. Quanto al primo punto, abbiamo già visto nell'articolo dedicato all'application manifest come i template di progetto per applicazioni Windows Store non includano alcuna immagine di default per il tile "wide" (mentre invece includono delle immagini di default per il tile quadrato, oltre che per lo splash screen, il logo per il Windows Store, ecc.).
Potete aggiungere al progetto l'immagine che preferite (purché della giusta dimensione), oppure usare le immagini fornite nella demo che accompagna questo articolo. In ogni caso, ricordatevi di referenziare l'immagine per il tile "wide" all'interno dell'application manifest, come mostrato nella seguente immagine:
Veniamo adesso al secondo punto, ossia ai dati d'esempio. Riprendendo l'esempio già illustrato in altri articoli di questa guida, aggiungiamo al progetto una nuova classe, denominata Bike, che rappresenta i nostri ormai classici modelli di mountain bike, e una classe Biz il cui unico metodo, GetAllBikes(), restituisce la relativa collezione. Questo che segue è il codice completo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Html.it.Demo.SharingSource
{
public class Biz
{
public List<Bike> GetAllBikes()
{
return new List<Bike>()
{
new Bike() { BikeName = "Specialized Stumpjumper" },
new Bike() { BikeName = "Scott Spark" },
new Bike() { BikeName = "Kona Abra Cadabra" },
new Bike() { BikeName = "Cannondale Jekill" },
new Bike() { BikeName = "Rocky Mountain Altitude" },
new Bike() { BikeName = "Bianchi Metanol" },
new Bike() { BikeName = "Santacruz Tallboy" },
new Bike() { BikeName = "Canyon Torque" }
};
}
}
public class Bike
{
public string BikeName { get; set; }
}
}
Nella pagina MainPage.xaml
aggiungiamo un controllo ListView
che mostri l'elenco dei modelli di mountain bike disponibili. Il codice da aggiungere è evidenziato in grassetto nel seguente listato:
<Page
x:Class="Html.it.Demo.SharingSource.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Html.it.Demo.SharingSource"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="BikeList" DisplayMemberPath="BikeName" />
</Grid>
</Page>
Nel costruttore della MainPage.xaml mettiamo in binding l'elenco delle mountain bike con il controllo ListView appena creato (le righe da aggiungere sono evidenziate in grassetto):
public MainPage()
{
this.InitializeComponent();
var biz = new Biz();
this.BikeList.ItemsSource = biz.GetAllBikes();
}
Se adesso premete F
5, dovreste ottenere il risultato mostrato nella prossima immagine:
Ora siamo pronti per utilizzare l'handler dell'evento SelectionChanged per modificare il tile dell'applicazione in modo da visualizzare il modello di mountain bike selezionata. Per far questo, modifichiamo il controllo ListView
in modo che contenga l'handler del relativo evento:
<ListView x:Name="BikeList"
DisplayMemberPath="BikeName"
SelectionChanged="BikeList_SelectionChanged"
/>
Nel code behind della pagina (MainPage.xaml.cs) aggiungiamo l'handler dell'evento, recuperiamo l'elemento selezionato dall'utente e assegniamolo alla variabile locale bike (ci tornerà utile a breve):
private void BikeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (BikeList.SelectedItem != null)
{
var bike = BikeList.SelectedItem as Bike;
}
}
Occupiamoci adesso di modificare il testo mostrato nella tile. A differenza delle classiche icone, ciascuna tile poggia in realtà su uno dei template XML messi a disposizione dall'SDK di Windows 8, che ne definisce contenuti e proprietà . Nel nostro esempio, useremo due template in particolare: "TileWideText03
" e "TileSquareText04
". I nomi utilizzati per i template sono in realtà piuttosto informativi della loro struttura. Il primo, ad esempio, può essere letto come "template per tile wide di solo testo disposto su un massimo di tre righe", mentre il secondo equivale a "template per tile quadrati di solo testo disposto su un massimo di quattro righe". Giusto per completezza, questa che segue è la struttura XML del primo dei due template:
<tile>
<visual>
<binding template="TileWideText03">
<text id="1">Text Header Field 1</text>
</binding>
</visual>
</tile>
Ciò chiarito, nell'handler dell'evento SelectionChanged modifichiamo il testo del tile per mostrare il modello di mountain bike selezionato per ultimo dall'utente. Di seguito riportiamo il metodo BikeList_SelectionChanged dopo le ultime modifiche (evidenziate in grassetto):
private void BikeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (BikeList.SelectedItem != null)
{
var bike = BikeList.SelectedItem as Bike;
if (bike != null)
{
StringBuilder sb = new StringBuilder();
sb.Append("<tile>");
sb.Append("<visual>");
sb.Append("<binding template='TileWideText03'>"); // template per tile wide
sb.Append("<text id='1'>Modello: " + bike.BikeName + "</text>");
sb.Append("</binding>");
sb.Append("<binding template='TileSquareText04'>"); // template per tile square
sb.Append("<text id='1'>" + bike.BikeName + "</text>");
sb.Append("</binding>");
sb.Append("</visual>");
sb.Append("</tile>");
}
}
}
Il codice è decisamente semplice: l'elemento visual della tile viene messo in binding con i due template sopra menzionati e, per ciascuno dei due, vengono definiti gli attributi visuali (in questo caso, il testo da mostrare).
Come si può facilmente intuire, le due tile possono essere impiegate per mostrare contenuti completamente diversi (ad esempio, solo testo in quello quadrato, testo e immagini per il tile wide), semplicemente cambiando il relativo template (nel nostro esempio, abbiamo usato un testo leggermente più lungo per il template "wide" rispetto a quello mostrato nel tile quadrato).
L'ultima cosa che ci resta da fare è informare il sistema operativo di aggiornare il nostro tile applicativo con il modello di bici selezionato dall'utente, in modo da mostrarlo sulla Start Page. Nel listato successivo, sono evidenziate in grassetto le linee da aggiungere all'handler dell'evento SelectionChanged
:
private void BikeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (BikeList.SelectedItem != null)
{
var bike = BikeList.SelectedItem as Bike;
if (bike != null)
{
StringBuilder sb = new StringBuilder();
sb.Append("<tile>");
sb.Append("<visual>");
sb.Append("<binding template='TileWideText03'>"); // template per tile wide
sb.Append("<text id='1'>Modello: " + bike.BikeName + "</text>");
sb.Append("</binding>");
sb.Append("<binding template='TileSquareText04'>"); // template per tile square
sb.Append("<text id='1'>" + bike.BikeName + "</text>");
sb.Append("</binding>");
sb.Append("</visual>");
sb.Append("</tile>");
var tileXml = new Windows.Data.Xml.Dom.XmlDocument();
tileXml.LoadXml(sb.ToString());
var tile = new Windows.UI.Notifications.TileNotification(tileXml);
Windows.UI.Notifications.TileUpdateManager.CreateTileUpdaterForApplication().Update(tile);
}
}
}
Per far notificare al sistema operativo di provvedere ad aggiornare la tile della nostra applicazione con i due nuovi template (e relativo contenuto), l'SDK di Windows 8 mette a disposizione la classe TileNotification, il cui obiettivo è quello di "preparare" l'aggiornamento di un tile (come si vedrà fra breve, esiste anche una classe BadgeNotification che, come si può facilmente intuire, "prepara" l'aggiornamento del badge applicativo), accettando nel costruttore il nuovo template in forma di documento XML.
var tileXml = new Windows.Data.Xml.Dom.XmlDocument();
tileXml.LoadXml(sb.ToString());
var tile = new Windows.UI.Notifications.TileNotification(tileXml);
Le prime due righe di codice non fanno altro che creare il documento XML da passare al costruttore della classe TileNotification
a partire dal "frammento" contenente i due template per il tile, costruito in precedenza.
A questo punto è sufficiente informare il sistema operativo che il tile è pronto per essere aggiornato con il nuovo contenuto. Per far questo possiamo utilizzare la classe Windows.UI.Notification.TileUpdateManager
, la quale espone - tra gli altri - il metodo CreateTileUpdaterForApplication. Questo metodo restituisce un oggetto di tipo TileUpdater che, tramite il metodo Update, provvede ad aggiornare il template e/o il contenuto del tile applicativo.
Premete F5
e selezionate un qualunque elemento dalla lista. Se tornate adesso alla Start Page tramite il tasto Windows, il vostro tile dovrebbe assumere adesso un aspetto simile a quello illustrato nella prossima immagine, corrispondente al primo dei template aggiunti al TileNotification
(TileWideText03
):
Provate adesso a cliccare sulla tile con il tasto destro del mouse, visualizzando così l'App Bar inferiore, in questo modo:
Selezionate il comando "Smaller" dell'App Bar per passare al tile quadrato, impostato come secondo template via codice (TileSquareText04
). Questo dovrebbe essere il risultato:
Il contenuto del nuovo tile rimarrà fino a quando non sarà sostituito da una nuova notifica, ovvero fino alla sua "data di scadenza". Tramite la proprietà ExpirationTime della classe TileNotification è infatti possibile definire il tempo di persistenza di una notifica nella Start Page, in modo da evitare di mostrare all'utente del contenuto non più attuale o rilevante (in altri termini, "scaduto").
Infine, un'ultima notazione sui tile: la classe TileUpdater espone, tra gli altri, anche il metodo EnableNotificationQueue. Questo metodo abilita un tile a ricevere e "accodare" fino a cinque notifiche (ad esempio, per mostrare tramite tile un estratto delle ultime cinque mail arrivate), da mostrare a rotazione. All'arrivo di una nuova notifica, questa va a "rimpiazzare" nella coda la notifica più "vecchia" e il ciclo continua.
Aggiungere un badge
Diamo l'ultimo "tocco" al nostro tile aggiungendovi un badge che, nel nostro caso (e per finalità puramente illustrative), si limiterà a indicare il numero di modelli di mountain bike effettivamente presenti nella nostra lista. Aggiungiamo al termine del metodo BikeList_SelectionChanged
le righe di codice evidenziate in grassetto nel prossimo listato:
private void BikeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (BikeList.SelectedItem != null)
{
var bike = BikeList.SelectedItem as Bike;
if (bike != null)
{
// (codice omesso per brevità)
string badgeXmlString = "";
var badgeXml = new Windows.Data.Xml.Dom.XmlDocument();
badgeXml.LoadXml(badgeXmlString);
var badge = new Windows.UI.Notifications.BadgeNotification(badgeXml);
Windows.UI.Notifications.BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(badge);
}
}
}
Il codice è molto simile a quello utilizzato per modificare il template (e relativo contenuto) della tile, solo che in questo caso il template XML utilizzato è decisamente più semplice. Da notare che l'attributo value dell'elemento badge è impostato con il numero di elementi che compongono la lista (da ricordare che il numero massimo visualizzabile nel badge è 99!), mentre se avessimo voluto usare uno dei simboli predefiniti avremmo dovuto impostare il relativo valore (ad esempio, "attention").
Se adesso eseguite l'applicazione, selezionate un elemento della lista e tornate alla Start Page, dovreste ottenere un risultato simile a quello mostrato nella prossima immagine:
In alternativa alla costruzione "artigianale" del template della tile tramite XML, Windows RT mette a disposizione anche un comodo enum, denominato TileTemplateType. Questo enum può essere utilizzato dalla classe TileUpdateManager
per recuperare il frammento XML corrispondente al template prescelto.
Nel nostro caso, ad esempio, per impostare lo stesso tipo di tile "wide" usato in precedenza avremmo potuto costruire il template XML da passare al costruttore della classe TileNotification
in questo modo:
var tileXml = Windows.UI.Notifications.TileUpdateManager.GetTemplateContent(Windows.UI.Notifications.TileTemplateType.TileWideText03);
var tileAttributes = tileXml.GetElementsByTagName("text");
tileAttributes[0].AppendChild(tileXml.CreateTextNode("Modello: " + bike.BikeName));
Un analogo enum è previsto anche per i template dei badge e prende il nome di BadgeTemplateType (in realtà questo enum è assai meno utile del precedente, dal momento che i template disponibili per i badge sono soltanto due, a seconda che il badge contenga un simbolo o un valore numerico).
Il codice necessario per utilizzare l'enum è comunque identico a quello utilizzato per il tile, con la differenza che in questo caso ad essere invocato è il metodo GetTemplateContent della classe BadgeUpdateManager
. Il codice risultante è illustrato qui di seguito:
var badgeXml = Windows.UI.Notifications.BadgeUpdateManager.GetTemplateContent(Windows.UI.Notifications.BadgeTemplateType.BadgeNumber);
var badgeNode = (XmlElement)badgeXml.SelectSingleNode("/badge");
badgeNode.SetAttribute("value", this.BikeList.Items.Count.ToString());
Microsoft mette a disposizione anche una libreria che semplifica ulteriormente il codice, astraendoci dai dettagli dei template XML. Nel codice seguente si vede la libreria all'opera.
var tileContent = TileContentFactory.CreateTileWideImageAndText01();
tileContent.TextCaptionWrap.Text = "Hello";
tileContent.Image.Src = imageUrl;
tileContent.Image.Alt = "";
var squareContent = TileContentFactory.CreateTileSquareImage();
squareContent.Image.Src = imageUrl;
squareContent.Image.Alt = "";
tileContent.SquareContent = squareContent;
TileUpdateManager.CreateTileUpdaterForApplication().Update(tileContent.CreateNotification());
Il codice si appoggia alla classe TileContentFactory per creare una istanza tipizzata del template a cui si possono valorizzare le relative proprietà dimenticandosi i dettagli del documento XML relativo.
Nel codice in produzione si utilizzerà sempre questa libreria, ma è importante capire il dettaglio implementativo, motivo per cui l'articolo si concentra sulla modalità di utilizzo nativo.
- Elenco, non estensibile, degli stati rappresentabili tramite un glifo.
- Elenco completo dei template per tile (su MSDN)
- dettagli di funzionamento del tile notification (su MSDN)
- Enumerazione completa TileTemplateType (su MSDN)