Windows 8, annunciato al largo pubblico durante la BUILD conference a settembre 2011, si propone con una interfaccia utente completamente rivista: è il primo Windows "senza Windows", nel senso che è la prima versione dalla sua nascita che non propone le classiche finestre che hanno fatto la sua fortuna negli anni passati.
In altri articoli avremo modo di parlare della nuova interfaccia e soprattutto della modalità di costruzione di applicazioni che sfruttano e si integrano con la nuova user experience. Questo articolo è dedicato allo Share Contract per entrare subito nel vivo di una delle novità più importanti del sistema operativo per noi sviluppatori di applicazioni.
La nuova interfaccia che ormai appare su i tutti i blog e articoli su Windows 8 si presenta come nell'immagine seguente:
Questa è una istallazione reale che presenta nella prima sezione una serie di Tile (un tile è la rappresentazione dell'applicazione nella schermata principale) con alcune applicazioni preinstallate durante la conferenza.
Socialite, ad esempio, è un'applicazione di "gestione" delle informazioni sui social network più famosi, News è un feed reader, mentre Build serviva a visualizzare l'elenco delle sessioni e a personalizzare l'agenda nella conferenza di presentazione.
PicStream, nella terza sezione di tile è una applicazione di visuallizzazione foto (che fanno riferimento ad un account flickr).
Quante volte ci è capitato di voler condividere una foto, gestita con il software A verso il software B? Oppure semplicemente prendere la foto creata con il software A e "spedirla" sul nostro profilo o album fotografico su Facebook?
Prendiamo ad esempio un caso semplicissimo: apro "paintplay", la versione touch (multi-touch in realtà) di Paint, e disegno con il mio ditone il logo della nostra prossima conferenza senza avere nessuna pretesa grafica:
Se volessi mettere nel mio album "loghi" su Facebook questa immagine, in Windows 7 dovrei:
- Salvare l'immagine sul mio disco locale
- Aprire il software di "gestione" del mio profilo su facebook (o il browser ovviamente)
- Cercare su disco il logo ed eseguire l'operazione desiderata
In Windows 8 è possibile condividere un dato da una applicazione all'altra senza bisogno di passare da un supporto di memorizzazione esterno alle due applicazioni. In pratica posso condividere l'immagine da "paintplay" verso tutte le applicazioni in grado di ricevere immagini, così come potrei condividere un testo verso tutte le applicazioni in grado di ricevere testi: questa funzionalità viene definita dallo Share Contract.
In pratica Windows 8 definisce una serie di contratti a cui le applicazioni Metro-style possono aderire per entrare in questo "gioco delle parti". Esiste un contratto che definisce come una applicazione Source possa condividere dei dati con una applicazione Target.
Nell'esempio precedente, "paintplay" è l'applicazione Source che implementa il contratto per esporre una certa tipologia di dato, ovvero un'immagine. Le API sono veramente semplici e ne vedremo un esempio fra pochissimo. Allo stesso modo, un'applicazione può implementare quanto serve per aderire al contratto come applicazione Target: sarà sufficiente aderire al contratto per poter ricevere le informazioni da altre applicazioni.
Per attivare, dal punto di vista dell'utente, la condivisione dall'applicazione source, è sufficiente aprire la barra dei Charm a destra tramite un movimento da destra verso sinistra al lato dello schermo. Nel caso di utilizzo del mouse è sufficiente spostarsi verso l'angolo in basso a sinistra dello schermo:
A parte l'ora attuale, accanto nel menu start appaiono i charm che consentono, fra le altre cose, di attivare la funzione Share. La funzione Share, appena selezionato il relativo charm, apre, sempre nella barra laterale a sinistra, l'elenco delle applicazioni che hanno aderito al contratto di share come target per la tipologia immagine. Nel nostro esempio appare Socialite che, come abbiamo detto, gestisce i social network più famosi:
La scritta principale "My PaintPlay Drawing" e la scritta immediatamente sotto vengono fornite dall'applicazione Source e sono ovviamente stringhe da passare alla funzione di condivisione nel codice (possiamo ovviamente chiedere all'utente queste informazioni).
Nel momento in cui l'utente sceglie l'applicazione target, Windows 8 richiederà all'applicazione target, tramite una chiamata alle API del contratto, di rispondere alla chiamata di "share".
Socialite, nel nostro esempio, risponde visualizzando una maschera in cui inserisce l'immagine ricevuta e propone all'utente il testo da inviare a Facebook per la pubblicazione sul profilo.
Se inseriamo un testo di esempio e premiamo Share In Facebook come proposto dalla maschera presentata dall'applicazione Target:
Questo semplice esempio ci fa capire la potenzialità dello Share Contract. Pensate ad una applicazione contabile che riceve informazioni sui contatti da outlook oppure un software di gestione fatture che riceve i PDF dall'applicazione gestionale o i dati sui clienti dal CRM.
L'importanza di avere un contratto sta nel fatto che le applicazioni non si devono conoscere a priori: le applicazioni Source espongono informazioni e le applicazioni Target possono ricevere queste informazioni. Quando l'utente installa un'altra applicazione (cosa che faremo tra poco creando anche il codice) che può ricevere immagini, questa nuova applicazione apparirà nell'elenco delle applicazioni target per tutte le applicazioni che condividono immagini.
Per fare un altro esempio che sfrutta sempre Socialite come target è la condivisione di un testo preso da un sito. Ad esempio, navigando sul sito della nostra conferenza DevCon selezioniamo un testo:
Usando sempre il Charm di condivisione si aprono le applicazioni che possono ricevere il testo: è importante ribadire che non stiamo parlando di una funzionalità di Internet Explorer, ma del fatto che la nuova versione di IE implementa il contratto source per condividere le informazioni testuali selezionate in una pagina web con altre applicazioni.
Nella barra a sinistra appare infatti in titolo della pagina, il link da dove è stato recuperato il testo e le due applicazioni installate che possono ricevere del testo ovvero quelle che implementano il contratto per fungere da target di elementi testuali.
Scegliendo sempre Socialite, come si può notare sotto, l'applicazione target mostra il testo (e non più l'immagine come nel caso di condivisione da "paintplay") da condividere su Facebook.
Realizzare un'applicazione Source in C#
Adesso che abbiamo capito l'idea, vediamo come implementare una applicazione Source in C#. Si parte con una applicazione Metro-style usando il template di Visual Studio 2011:
In questo primo esempio useremo il caso più semplice per arrivare diritti al punto che stiamo trattando senza distrazioni. In un prossimo articolo prenderemo l'output della webcam e condivideremo l'immagine.
Nel file MainPage.xaml
definiamo una ListView per visualizzare con gli stili di default un elenco di nomi:
<UserControl x:Class="ShareApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="768" d:DesignWidth="1366">
<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
<ListView x:Name="list" DisplayMemberPath="FullName"
SelectedValuePath="FullName" />
</Grid>
</UserControl>
Nella lista andremo a inserire una serie di persone il cui FullName sarà poi condiviso quando l'utente sceglie uno di loro e attiva la condivisione. Questo il codice più semplice che mi è venuto in mente per riempire la listview:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
namespace ShareApp
{
partial class MainPage
{
public MainPage()
{
InitializeComponent();
list.ItemsSource = new List<object>()
{
new { FullName = "Roberto Brunetti" },
new { FullName = "Paolo Pialorsi" },
new { FullName = "Marco Russo" },
new { FullName = "Luca Regnicoli" },
new { FullName = "Vanni Boncinelli" },
new { FullName = "Katia Egiziano" }
};
}
}
}
Possiamo provare con un F5 per vedere se intanto questo primo esperimento gira. Grafica a parte (che non ci interessa migliorare per questo esempio) dovremmo esserci:
A questo punto dobbiamo rispondere all'evento di share che il sistema (in realtà è un broker del servizio di condivisione) ci invierà quando l'utente preme il pulsante Share. Il modo più semplice di farlo dalla nostra applicazione è abbonarsi all'evento DataRequested utilizzando il metodo statico GetForCurrentView
della classe DataTransferManager direttamente dal codice della pagina che stiamo disegnando:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
namespace ShareApp
{
partial class MainPage
{
public MainPage()
{
InitializeComponent();
list.ItemsSource = new List<object>()
{
new { FullName = "Roberto Brunetti" },
new { FullName = "Paolo Pialorsi" },
new { FullName = "Marco Russo" },
new { FullName = "Luca Regnicoli" },
new { FullName = "Vanni Boncinelli" },
new { FullName = "Katia Egiziano" }
};
DataTransferManager.GetForCurrentView().DataRequested +=
new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(MainPage_DataRequested);
}
void MainPage_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
args.Request.Data.Properties.Title = "DevLeap Sharing";
if(list.SelectedItem != null)
{
args.Request.Data.Properties.Description = "Condivisione di " +
list.SelectedValue.ToString();
args.Request.Data.SetText(list.SelectedValue.ToString());
}
else
{
args.Request.FailWithDisplayText("Non hai selezioanto niente");
}
}
}
}
Il codice è molto semplice: impostiamo la proprietà Title, la proprietà Description e il testo da condividere. Nel caso di errori applicativi (come, nel nostro caso, il fatto che l'utente non abbia selezionato niente dalla lista) possiamo riportare un messaggio di errore.
Proviamo subito il caso di errore: questo il risultato.
Come si può notare, il codice è reale e funziona, come testimonia l'errore commesso durante la digitazione veloce della stringa di errore :). Proviamo il caso "corretto":
Il resto lo conosciamo: una volta scelta l'applicazione target, il controllo viene passato a quest'ultima sia per la visualizzazione che per l'operazione da eseguire sul package (questo il nome dell'insieme delle informazioni passate).
L'applicazione Target
Per l'applicazione Target, la prima operazione importante da compiere, è definire il tipo di dato che siamo in grado di ricevere. È anche importante definire una finestra che si adatti bene alla barra di condivisione.
Creato il progetto Target, si può aprire l'editor per la definizione dei tipi di dato da ricevere tramite un doppio click sul file Package.appxmanifest, file che il template di Visual Studio per le Metro-style app ha copiato all'interno del progetto.
Nella sezione Declaration occorre aggiungere Share Target in modo da informare il sistema che "possiamo essere il target di una condivisione". Una volta aggiunto Share Target si indicano i formati di dato supportati all'interno della sezione Data Formats.
Nella classe App (ovvero nel file App.xaml.cs) occorre effettuare l'override del metodo OnSharingTargetActivated: questo metodo viene invocato dal broker del sistema di sharing quando l'utente ha selezionato la nostra applicazione come target.
Nel metodo si istanzia la classe MainPage (o ovviamente quella che preferite) a cui dovremmo aggiungere un metodo che riceve gli argomenti forniti dal broker.
protected override void OnSharingTargetActivated(ShareTargetActivatedEventArgs args)
{
MainPage shareTargetPage = new MainPage();
shareTargetPage.ActivateTarget(args);
Window.Current.Content = shareTargetPage;
}
Andremo poi a costruire il metodo ActivateTarget nella della Main Page: all'interno di questo metodo possiamo recuperare il package in modo molto semplice.
public void ActivateTarget(ShareTargetActivatedEventArgs args)
{
Boolean contained;
ShareOperation shareOp = args.ShareOperation;
shareOp.Data.Contains(StandardDataFormats.Text, out contained);
if (contained)
{
label.Text = shareOp.Data.GetText();
}
}
Nell'esempio proposto, il testo condiviso è stato inserito in una semplice TextBlock definita nel file xaml.
Come abbiamo avuto modo di indicare in alcuni post, è possibile effettuare le stesse operazioni da applicazioni Metro-style scritte in html/javascript. Nell'esempio seguente, ad esempio, dopo aver configurato l'applicazione per ricevere i contenuti come abbiamo già visto per l'applicazione C#, la pagina di default recupera le informazioni dal package e le mostra all'interno di semplici tag html, ancora una volta senza nessuna pretesa grafica:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TargetAppHtml</title>
<!-- WinJS references -->
<link rel="stylesheet" href="/winjs/css/ui-dark.css" />
<script src="/winjs/js/base.js"></script>
<script src="/winjs/js/wwaapp.js"></script>
<!-- TargetAppHtml references -->
<link rel="stylesheet" href="/css/default.css" />
<script src="/js/default.js"></script>
<script>
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", activated);
function activated(e) {
if (e.kind ==
Windows.ApplicationModel.Activation.ActivationKind.shareTarget) {
share = e.shareOperation;
document.querySelector('h1').textContent = share.data.properties.title;
document.querySelector('h2').textContent =
share.data.properties.description;
document.querySelector('h3').textContent = share.data.getText();
}
}
</script>
</head>
<body>
<h1 />
<h2 />
<h3 />
</body>
</html>
È possibile lavorare in asincrono per operazioni che richiedono del tempo così come fornire un Quick Link che consente all'utente di "ritornare" in modo veloce alla nostra applicazione: ne parleremo in un prossimo articolo.