In un articolo precedente abbiamo introdotto la gestione "a contratti" delle applicazioni Windows 8 con lo Share Contract. In questo articolo invece ci occuperermo del Search Contract, la seconda tipologia di contratto esposto dal sistema operativo per consentire la ricerca di informazioni all'interno delle nostre applicazioni.
La nuova interfaccia, o per meglio dire la user experience di Windows 8, propone una funzionalità molto interessante per la ricerca di contenuti all'interno delle informazioni dell'utente, siano essi file, applicazioni, siti web, o elementi all'interno delle librerie dell'utente come la Picture Library o la Music Library.
L'idea è costruire una esperienza (il termine "esperienza" è voluto: si vedano anche i nostri articoli su Windows Phone 7 dove tale termine indica ciò che l'utente compie e soprattutto vive per eseguire una certa funzionalità) uniforme per ricercare contenuti all'interno del materiale utilizzato quotidianamente dall'utente.
L'esperienza di ricerca si attiva premendo Control+F
oppure facendo scorrere il dito dal bordo sinistro dello schermo per attivare la barra dei charm e scegliendo poi Search. In alternativa, possiamo spostare il puntatore del mouse nell'angolo in basso a sinistra, e premere poi Search.
Search apre quindi l'esperienza di ricerca e propone per default l'elenco delle applicazioni che soddisfano il criterio di ricerca che, ovviamente, all'inizio è ancora String.Empty
per dirla alla .NET.
L'utente può iniziare a digitare un testo all'interno dell'apposito box e ottenere, come ci si può aspettare, una vista filtrata dei risultati. In pratica il motore di search, tramite il contratto di Search, chiede a Windows stesso di "ricercare" il testo (denominato QueryText
) all'interno delle applicazioni.
Ad esempio, digitando "Not" all'interno del box si ottiene questo nella barra a sinistra dedicata alla ricerca:
I numerini accanto a Apps, Settings e Files, dimostrano come la ricerca sia stata effettutata "ovunque" all'interno del sistema operativo indicando, rispettivamente, le applicazioni che rispettano il criterio di ricerca, le impostazioni del Control Panel (sì, finalmente si può cercare all'interno delle singole opzioni del pannello di controllo) e dei file. Nel nostro caso ci sono 4 applicazioni, 43 impostazioni e 58 file che soddisfano il criterio.
Nella parte sinistra dello schermo, lasciando la selezione su Apps, vengono visualizzate le 4 applicazioni. Per i curiosi, Notepad è sempre lui, Sticky Notes è anche lui ben noto, Notespace è suo fratello in versione touch, Build Notifications (di cui "not" è parte del titolo) è il client di Team Foundation Server per ricevere le notifiche sulla build eseguite dal servizio di Build.
Nel momento in cui l'utente sposta la sua selezione su Settings o su Files, il sistema eseguirà la ricerca relativa. Ad esempio, sperando che non esca niente di strano dal PC, la stessa ricerca su files si presenta così:
La ricerca (o per meglio dire l'applicazione nativa che cerca nei files) presenta i risultati divisi per categoria: Documents e Other, oltre al classico All per visualizzare il tutto senza nessuna distinzione.
La sto prendendo un po' lunga per capire l'esperienza che vive l'utente e come essa si tradurrà in righe di codice.
L'interfaccia ripropone le ultime ricerche effettuate ("qui" e "a" erano le mie due ultime ricerche all'interno del sistema.
Sotto le tre voci App, Settings e Files, appaiono le applicazioni in cui è possibile ricercare informazioni ovvero le applicazioni che implementano il contratto di ricerca. Scegliendo Socialite, un'applicazione di "gestione" delle informazioni sui social network più famosi, viene ricercato il testo all'interno dell'applicazione stessa. Sarà compito dell'applicazione presentare l'interfaccia con i risultati di ricerca più appropriati. In pratica, il messaggio che sta dietro al Search Contract è il seguente: nessuno meglio dell'applicazione che gestisce dei dati sa presentare i dati stessi nel formato più utile per l'utente.
Ad esempio, se windows presentasse l'elenco dei miei amici su Facebook come se fossero file, sarebbe curioso rappresentare la data di ultima modifica di un amico, così come la sua dimensione e magari pure la sua estensione?
Socialite infatti presenta l'elenco in questo modo:
Realizzare una applicazione Metro-style per le ricerche
Adesso che abbiamo chiaro il meccanismo o, per meglio dire, l'experience dell'utente, vediamo come calare il tutto nelle API del semplice progetto che andiamo a costruire per ricercare informazioni all'interno di alcuni dati dell'applicazione.
I passi da ricordare sono
- L'applicazione deve indicare il supporto al search
- L'applicazione riceve un evento quando l'utente seleziona l'applicazione stessa dalla ricerca
- L'evento riceve il QueryText ovvero il testo digitato dall'utente
- L'applicazione può fornire suggerimenti per semplificare la ricerca
- L'applicazione deve presentare i risultati della ricerca
È possibile realizzare l'applicazione con qualunque linguaggio supportato da Win RT. Noi vedremo un esempio in XAML/C#. Per prima cosa occorre creare un progetto Metro-style:
È sufficiente aggiungere un item preconfigurato di tipo Search per effettuare le operazioni necessarie a:
- Indicare nel manifest il supporto al Search
- Preparare una pagina che visualizzerà i risultati della ricerca
- Inserire l'evento nel file App.xaml.cs per rispondere alla richiesta di ricerca
Il tutto si effettua tramite il classico Add New Item sul progetto:
Aggiunto questo item, il manifest che descrive le "capabilities" dell'applicazione si arricchisce della definizione di Search all'interno della sezione Declarations.
Questa impostazione è sufficiente per "apparire" nell'esperienza di Search: chiaramente, senza implementare il codice di ricerca si va da poche parti, ma è importante sottolineare che, a prescindere dall'effettiva ricerca, la dichiarazione consente all'applicazione di essere inclusa nella lista delle Searchable Apps.
La pagina per la visualizzazione dei risultati è alquanto scarna, nonostante contenga, in questa prima Developer Preview, gli stili inline. Il contenuto principale si presenta così:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="BackButton" Grid.Column="0" Click="BackButton_Click" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="PageTitle" Grid.Column="1" Text="{StaticResource ApplicationName}" Style="{StaticResource PageTitleStyle}" />
<TextBlock x:Name="ResultText" Grid.Column="2" Text='Results for ' Style="{StaticResource PageSubTitleStyle}"/>
<TextBlock x:Name="QueryText" Grid.Column="3" Text="{Binding QueryText}" Style="{StaticResource PageSubTitleStyle}"/>
</Grid>
<StackPanel x:Name="FiltersPanel" HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Horizontal" Grid.Row="1" Margin="120,0,0,0">
<RadioButton Content="{Binding AllFilter}" Style="{StaticResource FilterButtonStyle}" />
</StackPanel>
<StackPanel x:Name="ResultsPanel" Margin="0,0,0,60" Grid.Row="2" Orientation="Horizontal">
<!--Add your search results items here-->
</StackPanel>
</Grid>
La pagina presenta il classico pulsante Back
e il titolo della pagina in alto a sinistra e, grazie al template Search Contract, indica in due label (TextBlock
) il testo "Results for" e il testo di ricerca digitato dall'utente; quest'ultimo viene ricavato dalla proprietà QueryText che, come si può notare dal code behind preparato dal template mostrato sotto, è una proprietà dell'oggetto messo in binding sul data context.
La proprietà AllFilter
che viene messa in binding è rappresentata sulla user interface tramite il controllo RadioButton
.
Ecco il codice del code behind della pagina che ci viene proposto. Da notare il segnaposto "//TODO" conforme alle task di Visual Studio dove dovremmo inserire la nostra logica di ricerca.
public void Activate(SearchActivatedEventArgs args)
{
var queryText = args.QueryText;
//TODO: Application-specific searching logic
// Prepare bindable content
var bindableProperties = new PropertySet();
bindableProperties["QueryText"] = '"' + queryText + '"';
bindableProperties["AllFilter"] = "All (0)";
this.DataContext = bindableProperties;
// Display the results
this.PreviousContent = Window.Current.Content;
Window.Current.Content = this;
Window.Current.Activate();
}
Come si nota, QueryText e AllFilter sono due proprietà della classe PropertySet (è un Dictionary, in parole povere) che, all'interno del file XAML, sono incluse direttamente nelle espressioni di binding sulle "label".
Il metodo Activate della pagina inserita dal template viene richiamato dall'evento applicativo di cui abbiamo parlato e si presenta così nel file App.xaml.cs:
protected override void OnSearchActivated(SearchActivatedEventArgs args)
{
var searchResultsPage = new SearchSimple.SearchResultsPage1();
searchResultsPage.Activate(args);
}
In pratica quando l'utente sceglie la nostra applicazione, quest'ultima riceve l'evento OnSearchActivated che, come si nota dal codice precedente, istanzia e richiama la pagina dei risultati della ricerca. La pagina di ricerca valorizza le informazioni di base che devono apparire sulla user interface, come il testo digitato e un pulsante per gestire eventuali filtri sul contenuto (come abbiamo visto all'inizio dell'articolo), mentre lascia al developer la scelta sulla user interface da presentare.
A questo punto si può provare l'applicazione per vedere l'effetto a video. Poi implementeremo il codice per effettuare una semplice ricerca: