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
Socialite
PicStream
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 applicazione Source applicazione Target
Nell'esempio precedente, "paintplay" è l'applicazione Source
Per attivare, dal punto di vista dell'utente, la condivisione dall'applicazione source, è sufficiente aprire la barra dei Charm
A parte l'ora attuale, accanto nel menu start appaiono i charm che consentono, fra le altre cose, di attivare la funzione Share
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
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
Questo semplice esempio ci fa capire la potenzialità dello Share Contract
L'importanza di avere un contratto
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
Usando sempre il Charm di condivisione
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.
Figura 9. Condividere testo su FB con Socialite
(clic per ingrandire)
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
Nel file MainPage.xaml
<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
GetForCurrentView
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":
Figura 13. Esecuzione corretta
(clic per ingrandire)
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
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
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
<!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.