Sviluppare applicazioni per Windows Phone 8 ora in vendita!

Print Content | More
WP_20130509_002

Aggiornamento: il libro è ora disponibile anche in versione digitale, sempre sul sito della casa editrice, al prezzo di 29,90 € (contrariamente ai 34,90 € precedentemente dichiarati). Prossimamente in vendita anche nei principali store online.

In tanti mi avete contattato per chiedere informazioni sulla disponibilità via mail o tramite social network e, finalmente, posso segnalarvi che il mio libro “Sviluppare applicazioni per Windows Phone 8” è ora in vendita!

Al momento, il libro è acquistabile direttamente dal sito della casa editrice al prezzo di 49,90 €. A partire da settimana prossima sarà disponibile anche nelle principali librerie della Lombardia mentre, entro due settimane, sarà distribuito in tutta Italia. Per fine Maggio, infine, sarà disponibile anche la versione e-book, al prezzo di 34,90 €.

Il volume, interamente a colori, è composto da 656 pagine e contiene un’introduzione a cura di Marco Argenti, Senior Vice President della Developer Division di Nokia.

Per l’occasione, ho creato anche una sezione dedicata su questo blog: oltre alla descrizione del libro, trovate il download degli esempi di codice e, a breve, una pagina in cui segnalerò eventuali aggiornamenti sugli argomenti trattati emersi dopo la pubblicazione.

Se siete tra le persone che lo hanno acquistato o che hanno intenzione di acquistarlo, vi ricordo che, per qualsiasi feedback, segnalazione di refuso o richiesta di chiarimento, potete contattarmi usando l’apposito form di contatto.


Windows Phone

1 comments

Caliburn Micro e Windows Phone – Gestire l’Application Bar

Print Content | More

L’Application Bar è la croce e la delizia di tutti gli sviluppatori Windows Phone che utilizzano il pattern MVVM: tale controllo, infatti, vive “in un mondo a sè” e non fa parte del contesto della pagina. Per questo motivo, non eredita dalla classe base FrameworkElement (dalla quale derivano tutti gli altri controlli) e, di conseguenza, non supporta il binding. Non è possibile utilizzare i command, per collegare delle azioni agli eventi scatenati dalla pressione dei pulsanti, e non è possibile collegare delle proprietà del ViewModel alle proprietà Text e IconUri per gestire dinamicamente testi e icone.

Dato che, spesso e volentieri, questi limiti portano lo sviluppatore a “rompere” il pattern MVVM e a gestire l’Application Bar direttamente dal code behind, alcuni sviluppatori hanno realizzato delle implementazioni alternative della Application Bar, in grado di supportare il binding. Sono diverse le soluzioni disponibili: due delle migliori che ho trovato sono il Cimbalino Toolkit di Pedro Lamas e Caliburn Bindable App Bar by Kamran Ayub. Il primo toolkit utilizza un approccio basato sui behavior, che vengono applicati direttamente alla Application Bar nativa. Non lo approfondiremo nel corso di questo articolo, non perchè non sia una soluzione valida ma perchè non si sposa molto bene con Caliburn Micro: è perfetto, invece, se utilizzate MVVM Light come toolkit per le vostre applicazioni.

Tratteremo, invece, la seconda implementazione, che nasce proprio per supportare Caliburn e le sue convenzioni e che rimpiazza comletamente l’Application Bar standard.

Vediamo come usarla!

Aggiungere l’Application Bar al proprio progetto

La Caliburn Bindable App Bar è disponibile come pacchetto NuGet: semplicemente fate click con il tasto destro sul vostro progetto, scegliete Manage NuGet packages e cercate il pacchetto chiamato Caliburn.Micro.BindableAppBar. Una volta installato, dovete aggiungere il namespace seguente nello XAML per poterlo utilizzare:

xmlns:bab=”clr-namespace:Caliburn.Micro.BindableAppBar;assembly=Caliburn.Micro.BindableAppBar”

A questo punto potete aggiungere il controllo vero e proprio, che si chiama BindableAppBar. Fate attenzione però! Contrariamente alla Application Bar standard (che viene posizionata al di fuori della Grid principale dato che non fa parte della pagina), questo controllo deve essere inserito, invece, all’interno della Grid principale (mi riferisco al controllo Grid che, nel template standard, è chiamato LayoutRoot). Ecco un esempio:

<Grid x:Name="LayoutRoot" Background="Transparent"> 
    <Grid.RowDefinitions> 
        <RowDefinition Height="Auto"/> 
        <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 
  
    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 
        <TextBlock Text="Caliburn Micro" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/> 
        <TextBlock Text="Sample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 
    </StackPanel> 
  
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 
  
    </Grid> 
  
    <bab:BindableAppBar x:Name="AppBar"> 
        <bab:BindableAppBarButton x:Name="AddItem"
                                  Text="{Binding AddItemText}"
                                  IconUri="{Binding Icon}" 
                                  Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
                                  /> 
  
        <bab:BindableAppBarMenuItem x:Name="RemoveItem"
                                  Text="Remove"
                                  /> 
    </bab:BindableAppBar> 
</Grid>

Il controllo è molto semplice da utilizzare. All’interno del tag BindableAppBar potete aggiungere due tipologie di controlli: BindableAppBarButton, che è il pulsante con l’icona (ne potete aggiungere fino a 4) e BindableAppBarMenuItem, che invece rappresentano gli elementi testuali che vengono mostrati sotto le icone.

Entrambi condividono le stesse proprietà, dato che rappresentano un pulsante che può essere premuto per eseguire un’azione: l’unica differenza è che il controllo BindableAppBarButton ha una proprietà IconUri, che contiene il percorso dell’immagine che viene utilizzata come icona.

Entrambi i controlli condidono la stessa convenzione di Caliburn che viene utilizzata per le azioni: il valore della proprietà x:Name del controllo coincide con il nome del metodo, dichiarato nel ViewModel, che viene eseguito quando il pulsante viene premuto. In più, tutte le altre proprietà supportano il binding, inclusa Visibility, che permette di mostrare o nascondere un pulsante.

Prima di iniziare ad interagire con la Application Bar dal ViewModel c’è un’ulteriore passaggio da fare: aggiungere una convenzione personalizzata. Caliburn Micro, infatti, da la possibilità dagli sviluppatori di definire le proprie convenzioni, che vengono aggiunte a quelle già esistenti. Tali convenzioni vengono aggiunte nel bootstrapper, all’interno del metodo AddCustomConventions() che viene chiamato quando il boostrapper viene registrato.

Ecco il codice da inserire:

static void AddCustomConventions()
{
    ConventionManager.AddElementConvention<BindableAppBarButton>(
    Control.IsEnabledProperty, "DataContext", "Click");
    ConventionManager.AddElementConvention<BindableAppBarMenuItem>(
    Control.IsEnabledProperty, "DataContext", "Click");
}

Tramite questo codice stiamo praticamente aggiungendo una nuova convenzione per gestire l’evento Click del pulsante direttamente dal ViewModel.

Ora è il momento di passare al codice del ViewModel, per gestire le varie proprietà della BindableAppBar:

public class MainPageViewModel: Screen
{
 
    private string addItemText;
 
    public string AddItemText
    {
        get { return addItemText; }
        set
        {
            addItemText = value;
            NotifyOfPropertyChange(() => AddItemText);
        }
    }
 
    private Uri icon;
 
    public Uri Icon
    {
        get { return icon; }
        set
        {
            icon = value;
            NotifyOfPropertyChange(() => Icon);
        }
    }
 
    private bool isVisible;
 
    public bool IsVisible
    {
        get { return isVisible; }
        set
        {
            isVisible = value;
            NotifyOfPropertyChange(() => IsVisible);
        }
    }
 
    public MainPageViewModel()
    {
        AddItemText = "Add";
        Icon = new Uri("/Assets/AppBar/appbar.add.rest.png", UriKind.Relative);
        IsVisible = false;  
    }
 
    public void AddItem()
    {
        MessageBox.Show("Item added");
    }
 
    public void RemoveItem()
    {
        MessageBox.Show("Item removed");
    }
}

Se avete seguito gli altri post dedicati a Caliburn Micro la struttura di questo ViewModel dovrebbe esservi famigliare: abbiamo definito alcune proprietà e metodi, che sono collegati alla BindableAppBar tramite delle convenzioni. Quando il ViewModel viene inizializzato, definiamo il testo, l’icona e la visibilità di uno dei pulsanti nell’Application Bar. Si tratta di un approccio molto utile quando lo stato visivo dei pulsanti è dinamico e non “fisso” per tutto il ciclo di vita dell’applicazione. Prendiamo come esempio un’applicazione per leggere le ultime notizie: una delle funzionalità proposte potrebbe essere la possibilità di salvare la notizia in una lista di preferiti, tramite un pulsante ad hoc nella Application Bar. In questo caso, l’aspetto del pulsante deve cambiare in baso allo stato della notizia: se questa è già stata salvata tra i preferiti, probabilmente il testo del pulsante sarà “Rimuovi” e l’icona mostrerà il segno meno; se invece la news non fa parte dei preferiti, il pulsante avrà l’etichetta “Aggiungi” e l’icona mostrerà il segno più.

Con il ViewModel che abbiamo appena visto sarebbe semplice cambiare l’aspetto visivo del pulsante in base allo stato della notizia: sarebbe sufficiente agire sulle proprietà AddItemText e Icon per cambiare testo e icona del pulsante.

Anche la proprietà Visibility può essere comoda in molte situazioni: sempre riprendendo l’esempio precedente, ipotizziamo che l’applicazione consenta anche, sempre tramite un pulsante nella Application Bar, di creare una tile secondaria nella schermata Start che punti alla notizia. In tal caso, solo nel momento in cui l’applicazione viene aperta da una tile secondaria, vogliamo aggiungere un pulsante “Home” nella Application Bar per portare l’utente alla pagina principale dell’applicazione, dato che lo stack delle pagine è vuoto e quindi la pressione del pulsante Back la chiuderebbe direttamente. Nel nostro caso, invece, sarebbe sufficiente definire una proprietà nel ViewModel che rappresenti questa informazione e collegarla alla proprietà Visibility del pulsante, così da mostrarlo solo in caso di effettivo bisogno.


Windows Phone , Caliburn , MVVM

0 comments

Caliburn Micro e Windows Phone – Utilizzare i propri servizi

Print Content | More

In questa serie di post sull’utilizzo di Caliburn Micro in Windows Phone abbiamo imparato che il toolkit include molti helper e servizi, che vengono automaticamente registrati nel momento in cui, nel boostrapper, chiamiamo il metodo RegisterPhoneServices() della classe PhoneContainer. Abbiamo visto molti esempi di questi servizi, come il NavigationService e l’EventAggregator. Siamo stati in grado di ottenere un riferimento a tali classi semplicemente aggiungendo un parametro nel costruttore del ViewModel: Caliburn Micro, tramite il suo sistema integrato di dependency injection, è in grado di risolvere da solo le dipendenze.

Ma come comportarsi nel caso in cui abbiamo la necessità di registrare le nostre classi e i nostri servizi? Ipotizziamo che stiate sviluppando un’applicazione per leggere un feed RSS, che è in grado di fare il parsing dell’XML e di mostrare le notizie in una lista. In questo caso, potreste avere un servizio (ovvero una classe separata dal ViewModel) che si occupa di scaricare l’RSS e di convertirlo da una stringa piatta (l’XML) in una serie di oggetti che possiamo manipolare. Un approccio potrebbe essere quello di creare un’istanza del servizio direttamente nel ViewModel, come nell’esempio:

public MainPageViewModel() 
{
    IFeedService feedService = new FeedService();
     // do something with the feed service
}

Questo approccio, però, ha uno svantaggio. Ipotizziamo che vogliate fare dei test con dei dati fittizzi e, di conseguenza, vogliata utilizzare, al posto della classe FeedService, un’altra classe chiamata FakeFeedService che, invece di prelevare i dati dal feed RSS reale, li prenda da un file XML locale. In uno scenario reale, la vostra classe FeedService probabilmente sarebbe utilizzata da diversi ViewModel: di conseguenza, dovreste andare nel costruttore di ogni ViewModel e cambiare l’inizializzazione della classe nel modo seguente:

public MainPageViewModel() 
{
    IFeedService feedService = new FakeFeedService();
     // do something with the fake feed service
}

Un approccio migliore sarebbe di usare lo stesso adottato da Caliburn Micro: i servizi vengono registrati all’avvio, in questo modo è sufficiente aggiungere un parametro al costruttore del ViewModel affinchè il servizio venga automaticamente risolto e “iniettato” nel ViewModel. In questo modo, se dovete cambiare l’implementazione concreta del vostro servizio, dovrete farlo solo nel bootstrapper, quando il servizio viene registrato: automaticamente tutti i ViewModel inizieranno ad utilizzare la nuova classe.

Di conseguenza, ecco come cambia la definizione del ViewModel con questo nuovo approccio:

public MainPageViewModel(IFeedService feedService)
{
    //do something with the feed service
}

Registrare i propri servizi

Vediamo ora come implementare un vostro servizio e registrarlo, così da poterlo utilizzare con l’approccio sopra descritto.

Innanzitutto dovete creare un’interfaccia per il servizio, che descriva i metodi che la classe deve esporre. Si tratta di un passaggio molto importante, in quanto consente di cambiare, in maniera semplice, l’implementazione concreta di un servizio semplicemente registrandolo nel bootstrapper. Riprendendo l’esempio di prima, FeedService e FakeFeedService sono due implementazioni concrete differenti, ma si rifanno alla stessa interfaccia, dato che espongono gli stessi metodi: quelli per elaborare un feed RSS. Andremo perciò a creare l’interfaccia IFeedService e a registrarla nel costruttore del ViewModel.

public interface IFeedService
{
    Task<List<FeedItem>> GetNews(string url);
}

L’interfaccia descrive solamente un metodo, che utilizzeremo per recuperare l’elenco delle notizie: accetta in ingresso l’url del feed RSS e restituisce una collezione di oggetti di tipo FeedItem, che è una semplice classe che descrive una singola notizia:

public class FeedItem
{
    public string Title { get; set; }
    public string Description { get; set; }
    public Uri Url { get; set; }
}

Infine, ecco l’implementazione concreta della classe FeedService:

public class FeedService: IFeedService
{
    public async Task<List<FeedItem>> GetNews(string url)
    {
        WebClient client = new WebClient();
        string content = await client.DownloadStringTaskAsync(url);
 
        XDocument doc = XDocument.Parse(content);
        var result = doc.Descendants("rss").Descendants("channel").Elements("item").Select(x => new FeedItem
        {
            Title = x.Element("title").Value,
            Description = x.Element("description").Value
        }).ToList();
 
        return result;
    }
}

Questa classe contiene l’implementazione concreta dell’interfaccia IFeedService e, di conseguenza, del metodo GetNews(). All’interno di tale metodo andiamo ad utilizzare la classe WebClient per scaricare il feed: nello specifico, per comodità ho installato l’Async Pack di cui vi ho parlato in un post precedente, grazie al quale possiamo utilizzare il metodo asincrono DownloadStringTaskAsync(). Una volta ottenuto l’XML del feed RSS, utilizziamo LINQ TO XML per attraversare i nodi che lo compongono e creare una serie di oggetti di tipo FeedItem con le principali informazioni (titolo e descrizione).

Ora è tempo di registrare il nostro servizio, così da utilizzarlo nel ViewModel. La registrazione viene fatta nel bootrapper e dovrebbe esservi famigliare, dato che è lo stesso approccio utilizzato per la registrazione dei ViewModel: lo facciamo nel metodo Configure() della classe boostrapper.

protected override void Configure()
{
    container = new PhoneContainer(RootFrame);
 
    container.RegisterPhoneServices();
    container.PerRequest<MainPageViewModel>();
    container.PerRequest<IFeedService, FeedService>();
    AddCustomConventions();
}

Potete notare una differenza rispetto a quanto facciamo con i ViewModel: dato che, in questo caso, il nostro servizio utilizza un’interfaccia, dobbiamo dire al container che ogni qualvolta un ViewModel richiederà un oggetto di tipo IFeedService, sarà suo compito restituirgli un’istanza concreta della classe FeedService. Lo facciamo grazie al metodo PerRequest<T, Y>(), dove T è l’interfaccia e Y l’implementazione reale. Ora siamo in grado di usare il servizio nel nostro ViewModel per mostrare le notizie.

Ecco un esempio di XAML, all’interno della View, in grado di mostrare la collezione di oggetti di tipo FeedItem:

<StackPanel>
    <Button Content="Load website" x:Name="LoadWebsite"></Button>
    <ListBox x:Name="News">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=Title}"></TextBlock>
                    <TextBlock Text="{Binding Path=Description}"></TextBlock>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

Abbiamo un pulsante, che utilizzeremo per caricare il feed RSS, e una lista che, tramite la definizione dell’ItemTemplate, mostrerà le proprietà Title e Description (ovvero titolo e descrizione) della notizia.

Ed ecco la definizione del ViewModel:

public class MainPageViewModel: Screen
{
    private readonly IFeedService feedService;
 
    private List<FeedItem> news;
 
    public List<FeedItem> News
    {
        get { return news; }
        set
        {
            news = value;
            NotifyOfPropertyChange(() => News);
        }
    }
 
    public MainPageViewModel(IFeedService feedService)
    {
        this.feedService = feedService;
    }
 
    public async void LoadWebsite()
    {
        News = await feedService.GetNews("http://feeds.feedburner.com/qmatteoq_eng");
    }
}

Nulla di speciale da evidenziare se non che, nel costruttore del ViewModel, abbiamo aggiunto un parametro di tipo IFeedService: questo fa si che, grazie alla registrazione nel boostrapper fatta in precedenza, il ViewModel contenga in automatico un riferimento al servizio, che siamo in grado perciò di utilizzare nel momento in cui l’utente preme il pulsante e il metodo LoadWebsite() viene invocato. Nell’esempio, tramite il metodo GetNews() recuperiamo l’elenco di notizie pubblicate sul mio blog in inglese.

Passare dati da una pagina all’altra

Nel momento in cui abbiamo parlato di navigazione abbiamo evidenziato la possibilità di passare parametri nell’URL della pagina, così da poter scambiare informazioni tra le pagine. Il limite di questo approccio è che, trattandosi di parametri in query string, siamo in grado solamente di scambiare dati testuali, come stringhe o numeri. Nella maggior parte dei casi, invece, abbiamo la necessità di passare oggetti complessi. Ipotizziamo di voler espandere la nostra applicazione di esempio ed implementare una pagina per leggere il dettaglio della notizia: in tal caso, quello che vogliamo fare è passare l’intero oggetto FeedItem che è stato selezionato, così da poterne accedere a tutte le proprietà.

Un approccio che possiamo utilizzare è quello che abbiamo descritto in questo post: utilizzare un nostro servizio ad hoc, che passeremo ad ogni ViewModel.

public class DataService
{
    public FeedItem SelectedItem { get; set; }
}

La classe è molto semplice, dato che contiene solamente una proprietà di tipo FeedItem, nella quale andremo a salvare la notizia selezionata dall’utente.

Ora dobbiamo registrare questa nuova classe nel bootstrapper:

protected override void Configure()
{
    container = new PhoneContainer(RootFrame);
 
    container.RegisterPhoneServices();
    container.PerRequest<MainPageViewModel>();
    container.PerRequest<DetailPageViewModel>();
    container.PerRequest<IFeedService, FeedService>();
    container.Singleton<DataService>();
    AddCustomConventions();
}

In questa occasione possiamo vedere un nuovo tipo di registrazione, tramite il metodo Singleton<T>(). Qual è la differenza? Nel momento in cui registriamo una classe con il metodo PerRequest<T>(), ogni volta che all’interno dell’applicazione tentiamo di utilizzarla ci sarà restituita una nuova istanza. E’ l’approccio ideale per i ViewModel: nel nostro caso, ogni volta che la pagina di dettaglio viene caricata il suo contenuto deve essere cambiato, perchè deve essere mostrata la news selezionata; ha senso perciò che, ad ogni richiesta, ci venga restituita una nuova pagina con un nuovo ViewModel. Ecco perciò che la classe DetailPageViewModel viene registrata con il metodo PerRequest<T>(). Non è però la stessa situazione della classe DataService: in questo caso abbiamo la necessità di mantenere la stessa istanza della classe, perchè vogliamo che ogni ViewModel possa accedere al dato contenuto nella proprietà SelectedItem. Se ci facessimo restituire una nuova istanza ogni volta, il valore della proprietà andrebbe perso ad ogni richiesta. La soluzione è proprio quella di utilizzare il metodo Singleton<T>(), che registra l’istanza della classe come univoca, facendo si che venga restituita sempre la stessa ad ogni richiesta.

Ora dobbiamo aggiungere semplicemente un parametro di tipo DataService sia nel costruttore della classe MainPageViewModel, che in quello della classe DetailPageViewModel:

public class MainPageViewModel: Screen
{
    private readonly IFeedService feedService;
    private readonly INavigationService navigationService;
    private readonly DataService dataService;
 
    private List<FeedItem> news;
 
    public List<FeedItem> News
    {
        get { return news; }
        set
        {
            news = value;
            NotifyOfPropertyChange(() => News);
        }
    }
 
    private FeedItem selectedNew;
 
    public FeedItem SelectedNew
    {
        get { return selectedNew; }
        set
        {
            selectedNew = value;
            dataService.SelectedItem = value;
            navigationService.UriFor<DetailPageViewModel>().Navigate();
            NotifyOfPropertyChange(() => SelectedNew);
        }
    }
 
    public MainPageViewModel(IFeedService feedService, INavigationService navigationService, DataService dataService)
    {
        this.feedService = feedService;
        this.navigationService = navigationService;
        this.dataService = dataService;
    }
 
    public async void LoadWebsite()
    {
        News = await feedService.GetNews("http://feeds.feedburner.com/qmatteoq_eng");
    }
}

Nel ViewModel della pagina principale abbiamo aggiunto anche una proprietà di nome SelectedNew: se vi ricordate quanto spiegato nel post dedicato alle collezioni, in questo modo facciamo sì che questa venga automaticamente collegata all’elemento selezionato della lista. Dobbiamo però fare due modifiche al set della proprietà (che viene invocato ogni qualvolta il suo valore viene modificato, nel nostro caso quando viene selezionato un elemento dalla lista): la prima è quella di salvare, all’interno della classe DataService, l’elemento selezionato; la seconda è quella di scatenare la navigazione verso la pagina di dettaglio.

E per quanto riguarda la pagina di dettaglio? La View, semplicemente, si limiterà a mostrare le informazioni della news selezionata:

<StackPanel>     
    <TextBlock x:Name="Title" />     
    <TextBlock x:Name="Description" />
</StackPanel>

Il ViewModel conterrà semplicemente due proprietà, Title e Description, che saranno valorizzate con le informazioni recuperate dal DataService:

public class DetailPageViewModel: Screen
{
    private string title;
 
    public string Title
    {
        get { return title; }
        set
        {
            title = value;
            NotifyOfPropertyChange(() => Title);
        }
    }
 
    private string description;
 
    public string Description
    {
        get { return description; }
        set
        {
            description = value;
            NotifyOfPropertyChange(() => Description);
        }
    }
 
    public DetailPageViewModel(DataService dataService)
    {
        Title = dataService.SelectedItem.Title;
        Description = dataService.SelectedItem.Description;
    }
}

Anche in questo caso abbiamo aggiunto un parametro di tipo DataService nel costruttore: dato che, nel boostrapper, lo abbiamo registrato come singleton, il risultato è che l’istanza che ci sarà passata è la stessa che è stata definita nel MainPageViewModel: di conseguenza, la proprietà SelectedItem della classe DataService sarà valorizzata con la notizia scelta dall’utente nella pagina precedente.

Come al solito, vi lascio a disposizione un progetto di esempio con cui sperimentare le funzionalità descritte in questo post. Buon lavoro!


Windows Phone , Caliburn , MVVM

0 comments

Prossimi appuntamenti: Community Days, DotNetCampus, Intel MeetUp e altro ancora

Print Content | More

Periodo ricco di appuntamenti per gli sviluppatori e per le community d’Italia! Vi segnalo alcuni degli eventi più interessanti nel prossimo periodo.

Community Days

Dopo la tappa di Milano, tornano i Community Days e questa volta si spostano a Catania, per offrire anche agli sviluppatori del Sud Italia due giorni di sessioni e lab su Windows 8, Windows Phone, Azure e Web. Avrò il piacere di essere presente anche io a rappresentare DotNetLombardia, a dare una mano ai laboratori e a tenere una sessione sulla distribuzione di applicazioni Windows Phone: lo Store, gli scenari Enterprise e l’in app-purchase. L’appuntamento è per il 20 e 21 Maggio presso la Cittadella Universataria di Catania. Trovate l’agenda completa, le informazioni logistiche e i link per iscrivervi sul sito ufficiale. Attenzione che i laboratori su Windows 8, Windows Phone e Azure richiedono una registrazione separata rispetto a quella tradizionale per le giornate.

DotNetCampus

Anche il DotNetCampus si ripete e, dopo la tappa di Roma, propone altri due appuntamenti a Cosenza (il 15 Maggio presso la sede dell’Università della Calabria) e a Cesena (il 14 Giugno, presso il TechnoGym Village). Sarò presente anche in questa occasione, proponendo una sessione dedicata all’accesso ai dati locali in Windows Phone: database, isolated storage e file sharing. A rappresentare DotNetLombardia, con me, ci sarà anche Roberto, che terrà due sessioni dedicate a Windows Phone e ad Azure.

Trovate tutte le indicazioni, l’agenda e i link per iscrivervi ad entrambe le tappe sul sito ufficiale.

Windows Azure Conference

DotNetLombardia e Microsoft propongono insieme una giornata di approfondimento dedicata alle novità recentemente annunciate su Azure, suddivisa in due momenti: uno più formativo, al mattino, con sessioni su tematiche come i Mobile Service o lo sviluppo e il deploy di applicazioni web, e uno più pratico, con laboratori e ampio spazio alle domande. L’appuntamento è per il 6 Maggio presso il Microsoft Innovation Campus di Peschiera Borromeo (MI). Iscrizioni e maggiori dettagli sulla pagina ufficiale.

Intel MeetUp – The Natural User Interface Episode

Anche gli amici di Intel propongono, Sabato 4 Maggio a Bologna, un evento molto interessante dedicato alle Natural User Interface, in collaborazione con la community emiliana DotDotNet. Si parlerà di Perceptual Computing con le tecnologie di Intel, di Kinect e del nuovo Leap Motion. Se volete scoprire le ultime novità sulle nuove modalità di interazione con le più recenti tecnologie, non potete mancare! Agenda e iscrizioni sul sito ufficiale.

Tutto quello che avreste voluto sapere sull'accesso ai dati (e non avete mai osato chiedere)

Gli amici di DotNetToscana propongono, Sabato 18 Maggio a Pisa, una giornata completamente dedicata all’accesso ai dati in Windows Phone e Windows 8: si parlerà di SQLite, WebAPI, Mobile Service e SkyDrive. Se siete di quelle parti non perdetevelo perchè l’agenda è decisamente interessante. Informazioni e iscrizioni sul sito ufficiale.

Spring Event by Visual Basic Tips & Tricks

Visual Basic Tips & Tricks, una delle community italiane storiche, propone Sabato 8 Giugno a Vicenza una mattinata di approfondimento sulle nuove tecnologie web e cloud di Microsoft. Si parlerà di Azure, SignalR e LightSwitch, l’ottimo strumento di Microsoft per realizzare in maniera semplice e veloce applicazioni business. Iscrizioni e agenda sul sito ufficiale.

Web e ASP.NET Live

Gli eventi community sono da sempre il modo migliore per avvicinarsi alle nuove tecnologie e, allo stesso tempo, espandere la propria rete di contatti e conoscere nuove persone. Non sempre però si ha la possibilità di partecipare fisicamente. Vi farà piacere sapere, perciò, che ASPItalia ha organizzato un pomeriggio dedicato alle ultime novità Microsoft per il Web e che sarà tramesso in streaming online: tra gli argomenti trattati le Single Page Application, SignalR, WebAPI e tanto altro ancora, a cura dei membri di ASPItalia. Pur essendo un evento esclusivamente online, è comunque necessario iscriversi sul sito ufficiale, dove trovate anche l’agenda completa. L’appuntamento è per il 16 Maggio.


Microsoft , DotnetCampus , Community Days , Intel

0 comments

Caliburn Micro e Windows Phone – Utilizzare i launcher e i chooser

Print Content | More

Nel post precedente della serie abbiamo visto come funzioni l’infrastrattura dei messaggi integrata in Caliburn Micro. In questo post vedremo come utilizzare i launcher e i chooser in un ViewModel: i due argomenti sono strettamente collegati, dato che per eseguire questo compito Caliburn Micro utilizzato un tipo speciale di messaggio. Infatti, per interagire con launcher e chooser andremo ad utilizzare la classe IEventAggregator che abbiamo imparato ad utilizzare in precedenza. La differenza, in questo caso, sarà che i messaggi saranno “nascosti” e già inclusi all’interno del toolkit. Iniziamo!

Do per scontato che, se state leggendo questo blog, dato che MVVM è un argomento “avanzato”, sappiate già cosa sono i launcher e i chooser. In caso contrario, vi basti sapere per ora che sono un meccanismo che il sistema operativo mette a disposizione per interagire con le applicazioni native: ad esempio, per mostrare una posizione nell’applicazione Mappe o per importare un contatto dall’hub People; o ancora, inviare un SMS tramite l’applicazione Messaggi.

I launcher

Vediamo come interagire con i launcher, ovvero i task che sono utilizzati per demandare un’operazione ad un’applicazione nativa ma non si aspettano dati di ritorno: il nostro esempio sarà basato sulla classe MapsTask, che consente di mostrare una posizione nell’applicazione Mappe. Do per scontato che abbiate già creato il progetto base utilizzando Caliburn Micro, perciò abbiate già a disposizione una View collegata al relativo ViewModel tramite l’apposita convenzione che abbiamo imparato ad usare nei primi post.

Nella View aggiungiamo un pulsante, che useremo per eseguire il launcher:

<StackPanel>
    <Button Content="Launch map" x:Name="LaunchMap" />
</StackPanel>

Come sempre, grazie alle convenzioni di Caliburn, questa dichiarazione fa si che, al click sul pulsante, venga eseguito un metodo dal nome LaunchMap dichiarato nel ViewModel. Diamo uno sguardo al codice:

public class MainPageViewModel: Screen
{
    public MainPageViewModel(IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
        eventAggregator.Subscribe(this);
    }
 
    public void LaunchMap()
    {
        eventAggregator.RequestTask<MapsTask>(task =>
                                                  {
                                                      task.SearchTerm = "Milan";
                                                  });
    }
}

Come abbiamo potuto vedere nel post dedicato ai messaggi, è sufficiente aggiungere un parametro nel costruttore del ViewModel di tipo IEventAggregator per ottenere un riferimento all’oggetto da utilizzare per interagire con i messaggi. Il primo passaggio è sottoscriversi alla ricezione, utilizzando il metodo Subscribe(), passando come parametro la parola chiave this (dato che vogliamo abilitare alla ricezione il ViewModel stesso).

Nel metodo LaunchMap() utilizziamo la classe EventAggregator, chiamando uno degli extension method aggiunti alla versione di Caliburn Micro per Windows Phone: RequestTask<T>(), dove T è la classe che rappresenta il launcher che vogliamo eseguire (sono quelle contenute all’interno del namespace Microsoft.Phone.Tasks). Come parametro possiamo passare un delegate (nell’esempio, ne utilizziamo uno anonimo): si tratta di un’operazione necessaria per tutti quei launcher o chooser che hanno bisogno di alcune informazioni per funzionare correttamente. Nel nostro esempio, impostiamo la proprietà SearchTerm del task, per specificare la posizione che vogliamo cercare nella mappa. Se dobbiamo utilizzare un launcher che non richiede alcuna informazione in input (come il MarketplaceDetailTask), possiamo semplicemente non passare alcun parametro al metodo.

Se provate questa semplice applicazione sul telefono, vedrete l’applicazione Mappe aprirsi e localizzare la città di Milano nel momento in cui premete il pulsante.

I chooser

I chooser funzionano in un modo leggermente differente: il modo in cui andremo ad eseguirli è lo stesso deie launcher ma, in questo caso, ci aspettiamo anche un risultato. Come già detto all’inizio del post, l’utilizzo di launcher e chooser con Caliburn è basato sui messaggio: ecco perciò che il modo in cui gestiamo il valore di ritorno è lo stesso che abbiamo visto in precedenza per ricevere un messaggio. Facciamo una prova utilizzando il chooser PhoneNumberChooserTask, che può essere utilizzato per importare il numero di telefono di un contatto dalla rubrica.

Prima aggiungiamo il solito pulsante nella View:

<StackPanel>
    <Button Content="Open contact" x:Name="OpenContact" />
</StackPanel>

Ora diamo uno sguardo al ViewModel:

public class MainPageViewModel: Screen, IHandle<TaskCompleted<PhoneNumberResult>>
{
    private readonly IEventAggregator eventAggregator;
 
    public MainPageViewModel(IEventAggregator eventAggregator, INavigationService navigationService)
    {
        this.eventAggregator = eventAggregator;
 
        eventAggregator.Subscribe(this);
    }
 
    public void OpenContact()
    {
        eventAggregator.RequestTask<PhoneNumberChooserTask>();
    }
 
    public void Handle(TaskCompleted<PhoneNumberResult> message)
    {
        MessageBox.Show(message.Result.DisplayName);
    }
}

Il modo in cui utilizziamo un chooser è lo stesso che abbiamo visto per il launcher: utilizziamo il metodo RequestTask<T>() dell’oggetto EventAggregator, passando come valore di T il tipo di chooser che vogliamo utilizzare. In questo caso, rispetto a prima, non passiamo alcun parametro, dato che questo chooser non richiede nessuna informazione in ingresso per funzionare. Per gestire il valore di ritorno (quindi il numero della rubrica scelto dall’utente) utilizziamo lo stesso approccio visto nei messaggi: facciamo ereditare il ViewModel dalla classe IHandle<T>, dove T è di tipo TaskCompleted<T>. Questo secondo T, a sua volta, è il tipo restituito dal chooser (nel nostro caso, un oggetto di tipo PhoneNumberResult).

Ereditando da questa interfaccia, saremo costretti ad implementare il metodo Handle(), che riceve come parametro il risultato restituito dal chooser. Sta a noi decidere cosa farne: nell’esempio, ci limitiamo a mostrare il valore della proprietà DisplayName (che contiene nome e cognome del contatto).

Come gestire correttamente il ciclo di vita dei launcher e chooser

C’è un problema nell’usare l’architettura dei messaggi per gestire launcher e chooser. Quando abilitate un ViewModel alla ricezione di messaggi utilizzando il metodo Subscribe(), la sottoscrizione viene mantenuta attiva fintanto che l’istanza del ViewModel viene tenuta in memoria. Nel caso dei launcher e dei chooser questo può causare qualche problema: se ricordate il post precedente, eravamo in grado di sfruttare i messaggi per scambiare informazioni tra due ViewModel; in questo caso, invece, utilizziamo i messaggi per scambiare informazioni all’interno del ViewModel stesso (dato che si occupa sia di inviarlo, che di riceverlo). Se, ad esempio, spostaste il metodo OpenContact() che abbiamo appena visto in un altro ViewModel (ad esempio, una seconda pagina), ma manteneste il MainPageViewModel abilitato alla ricezione di messaggi di tipo TaskCompleted<PhoneNumberResult>, notereste che il MainPageViewModel continuerebbe a rispondere all’attivazione del chooser, anche se venisse scatenata da un altro ViewModel.

Questo scenario si applica soprattutto quando parliamo del MainPageViewModel, ovvero il ViewModel che è collegato alla pagina principale dell’applicazione: per questo motivo, la sua istanza viene sempre mantenuta attiva, fino al momento in cui l’applicazione non viene chiusa, al contrario di quanto avviene per le altre pagine (se siete nella seconda pagina della vostra applicazione e tornate alla pagina principale, questa, assieme al relativo ViewModel, viene dismessa).

Il modo migliore per gestire questa casistica è quello di usare gli eventi di navigazione che abbiamo imparato ad utilizzare in un post precedente ed ereditare il nostro ViewModel dalla classe Screen: in questo modo possiamo chiamare il metodo Subscribe() della classe EventAggregator nel momento in cui l’utente naviga verso la pagina (sfruttando il metodo OnActivate()) e, viceversa, utilizzare il metodo Unsubscribe() nel momento in cui l’utente lascia la pagina (sfruttando il metodo OnDeactivate()). Con questo approccio, nel momento in cui l’utente si sposta dalla pagina corrente verso un’altra pagina, questa non è più abilitata alla ricezione dei messaggi e, di conseguenza, ignorerà qualsiasi interazione con i launcher e i chooser.

Ecco un esempio di come appare il ViewModel aggiornato:

public class MainPageViewModel: Screen, IHandle<TaskCompleted<PhoneNumberResult>>
{
    private readonly IEventAggregator eventAggregator;
 
    public MainPageViewModel(IEventAggregator eventAggregator)
    {
        this.eventAggregator = eventAggregator;
    }
    protected override void OnActivate()
    {
        eventAggregator.Subscribe(this);
        base.OnActivate();
    }
 
    protected override void OnDeactivate(bool close)
    {
        eventAggregator.Unsubscribe(this);
        base.OnDeactivate(close);
    }
 
    public void OpenContact()
    {
        eventAggregator.RequestTask<PhoneNumberChooserTask>();
    }
 
    public void Handle(TaskCompleted<PhoneNumberResult> message)
    {
        MessageBox.Show(message.Result.DisplayName);
    }
}

Come potete notare, non chiamiamo più il metodo Subscribe() della classe EventAggregator nel costruttore, ma lo abbiamoi spostato nel metodo OnActivate().

Se volete fare qualche esperimento con quanto appreso in questo post, di seguito trovate il link per scaricare un progetto di esempio.


Windows Phone , MVVM , Caliburn

0 comments

Slide e demo del DotNetCampus

Print Content | More

Sabato si è svolto a Roma, nella cornice dell’Università di Roma Tre, il DotNetCampus, un evento organizzato da DevLeap in collaborazione con diversi sponsor che mette insieme tante realtà che ruotano attorno al mondo Microsoft: community, MVP, studenti, aziende e quant’altro. Anche noi di DotNetLombardia eravamo là, con un nostro stand e con la presenza mia e di Roberto, con il quale abbiamo proposto sessioni riguardanti Windows Phone e Windows Azure.

Nello specifico, ho tenuto una sessione dedicata all’accesso ai dati locali in Windows Phone 8: le nuove API per lo storage, i database disponibili e la nuova funzionalità di data sharing, per condividere dati con altre applicazioni.

La giornata è stata magnifica: tantissima gente, molto interesse verso gli argomenti proposti e tante occasioni, sia per noi speaker e membri delle community che per i partecipanti, di conoscere e incontrare altre persone.

Di seguito, vi propongo le slide e le demo utilizzate durante la mia sessione. Potete fare riferimento a questo post per tutti i dettagli su come installare e utilizzare SQLite nella vostra applicazioni Windows Phone 8.

Per qualsiasi dubbio, potete contattarmi tramite il form apposito!


Windows Phone , DotnetCampus

0 comments

Caliburn Micro e Windows Phone – Messaggi

Print Content | More

Durante lo sviluppo di un’applicazione con il pattern MVVM capita frequentemente di dover scambiare dati tra un ViewModel e l’altro, oppure di dover creare un canale di comunicazione tra la View e il ViewModel (ad esempio, per avviare un’animazione in seguito ad un’azione che si è scatentata nel ViewModel).

La soluzione più utilizzata in queste situazioni è lo scambio di messaggi: tutti framework di MVVM espongono una serie di classi ed helper per gestire questo scenario.

Cos’è un messaggio? Si tratta di una semplice classe, che può avere una o più proprietà, che rappresentano le informazioni da scambiare. Lo scambio di messaggi, solitamente, segue il flusso seguente:

  • Il ViewModel prepara un messaggio, creando una nuova istanza della classe che lo rappresenta, e lo spedisce;
  • Uno o più ViewModel si sottoscrivono per ricevere il messaggio: in tal caso, ogni qualvolta un ViewModel ne spedisce uno di quel tipo specifico, i ViewModel ricevono una notifica, così che possano gestirlo di conseguenza ed eseguire una o più operazioni..

Vediamo come implementare questo scenario utilizzando Caliburn Micro: andremo a creare due View, con i relativi ViewModel. La prima pagina conterrà un pulsante, che invierà un messaggio contente una stringa (un nome) all’altro ViewModel, così da mostrarlo nella seconda pagina.

Il primo passo è quello di creare il progetto: seguendo i tutorial precedenti creiamo un’applicazione composta da due pagine con i relativi ViewModel.

Prima di implementare il codice vero e proprio necessario per scambiare i messaggi, prepariamo tutta l’infrastruttura necessaria. La prima cosa da fare è aggiungere, nella prima pagina, un controllo TextBox e un pulsante: il primo mostrerà l’informazione ricevuta dal messaggio, il secondo invece lo useremo per portare l’utente alla seconda pagina.

Aprite la pagina principale dell’applicazione (solitamente il file MainPage.xaml) e, all’interno del controllo Grid identificato dal nome ContentPanel, aggiungete il seguente codice XAML:

<StackPanel>
    <TextBox x:Name="Name" />
    <Button Content="Go to page 2" x:Name="GoToPage2" />
</StackPanel>

Anche in questo caso utilizziamo le convenzioni di Caliburn che abbiamo già imparato a conoscere: il controllo TextBox sarà collegato ad una proprietà chiamata Name nel ViewModel, mentre il pulsante eseguirà il metodo GoToPage2, sempre dichiarato all’interno del ViewModel.

Ecco invece la definizione del ViewModel:

public class MainPageViewModel: Screen 
{ 
    private string name; 
  
    public string Name 
    { 
        get { return name; } 
        set
        { 
            name = value; 
            NotifyOfPropertyChange(() => Name); 
        } 
    } 
  
    public MainPageViewModel(INavigationService navigationService) 
    { 
        this.navigationService = navigationService; 
    } 
  
    public void GoToPage2() 
    { 
        navigationService.UriFor<SecondPageViewModel>().Navigate(); 
    } 
}

Se avete seguito i post precedenti non dovreste notare nulla di particolare: oltre alla proprietà Name, è presente un riferimento alla classe NavigationService per gestire la navigazione.

Ora passiamo alla seconda pagina. Ecco lo XAML:

<StackPanel> 
    <Button Content="Send message" x:Name="SendMessage" /> 
</StackPanel>

Inseriamo solamente un pulsante, che eseguirà il metodo SendMessaage() dichiarato nel ViewModel. Ora le cose iniziano a farsi interessanti: ecco la definizione del ViewModel, che contiene l’infrastruttura base per inviare il messaggio.

public class SecondPageViewModel: Screen 
{ 
    private readonly IEventAggregator eventAggregator; 
  
    public SecondPageViewModel(IEventAggregator eventAggregator) 
    { 
        this.eventAggregator = eventAggregator; 
    } 
  
    public void SendMessage() 
    { 
        eventAggregator.Publish(new SampleMessage("Matteo")); 
    } 
}

La classe utilizzata per la gestione dei messaggi si chiama EventAggregator: analogamente a quanto avviene con il NavigationService, si tratta di uno dei servizi integrati in Caliburn. E’ sufficiente, perciò, aggiungere un parametro di tipo IEventAggregator nel costruttore affinchè venga risolto automaticamente. Inviare un messaggio è molto semplice: è sufficiente chiamare il metodo Publish() passando come parametro l’oggetto che rappresenta il messaggio da inviare. Come già anticipato in precedenza, i messaggi sono rappresentati da una semplice classe, che può contenere una o più proprietà. Ecco la definizione della classe SampleMessage:

public class SampleMessage 
{ 
    public string Name { get; set; } 
      
    public SampleMessage(string name) 
    { 
        Name = name; 
    } 
}

La classe espone una proprietà chiamata Name, che viene valorizzata tramite una proprietà nel costruttore: in questo modo, nel ViewModel possiamo creare una nuova istanza della classe SampleMessage passando come valore la stringa “Matteo”.

A questo punto la classe EventAggregator, che rappresenta il nostro “postino”, ha spedito il messaggio. Come facciamo a riceverlo? Dobbiamo tornare nel primo ViewModel ed effettuare alcune modifiche:

public class MainPageViewModel: Screen, IHandle<SampleMessage> 
{ 
    private readonly IEventAggregator eventAggregator; 
    private readonly INavigationService navigationService; 
    private string name; 
  
    public string Name 
    { 
        get { return name; } 
        set
        { 
            name = value; 
            NotifyOfPropertyChange(() => Name); 
        } 
    } 
  
    public MainPageViewModel(IEventAggregator eventAggregator, INavigationService navigationService) 
    { 
        this.eventAggregator = eventAggregator; 
        this.navigationService = navigationService; 
  
        eventAggregator.Subscribe(this); 
    } 
  
    public void GoToPage2() 
    { 
        navigationService.UriFor<SecondPageViewModel>().Navigate(); 
    } 
  
   
    public void Handle(SampleMessage message) 
    { 
        Name = message.Name; 
    } 
}

Il primo passaggio è far ereditare il ViewModel dalla classe IHandle<T>, dove T è il tipo di messaggio che vogliamo ricevere. Nell’esempio, dato che il ViewModel della seconda pagina spedisce un messaggio d tipo SampleMessage, lo facciamo ereditare dalla classe IHandle<SampleMessage>.

Quando ereditiamo da quest’interfaccia siamo obbligati a implementare, all’interno del ViewModel, il metodo Handle(T message), che riceve come parametro il messaggio spedito dall’altro ViewModel. Nel nostro caso, il parametro è di tipo SampleMessage: ecco perciò che siamo in grado di recuperare il valore della proprietà Name del messaggio e di assegnarlo alla proprietà con lo stesso nome del ViewModel.

C’è un ulteriore passaggio da mettere in atto prima di provare l’applicazione: è necessario abilitare il ViewModel alla ricezione dei messaggi. Possiamo farlo grazie al metodo Subscribe() esposto dalla classe EventAggregator: così come abbiamo fatto nel secondo ViewModel, dobbiamo aggiungere nel costruttore un parametro di tipo IEventAggregator e chiamare il metodo Subscribe() passando un riferimento al ViewModel che vogliamo registrare (dato che si tratta del ViewModel stesso, possiamo usare la parola chiave this).

Il gioco è fatto! Se ora provate l’applicazione e, nella seconda pagina, premete il pulsante Send message, dopodichè con il tasto Back tornate alla pagina precedente, troverete il nome Matteo all’interno del controllo TextBox.

Comunicazione tra la View e il ViewModel

In alcuni casi può sorgere la necessità di creare un canale di comunicazione tra la View e il ViewModel, per gestire le animazioni o per gestire alcune tipologie di eventi che non supportano il binding.

L’approccio è lo stesso che abbiamo visto in precedenza: l’unica differenza è che, dato che si tratta di una View e non di un ViewModel, Caliburn Micro non è in grado di risolvere in automatico la dipendenza dalla classe IEventAggregator. Non è sufficiente, perciò, aggiungere un parametro di tipo IEventAggregator al costruttore della pagina: si scatenerà un’eccezione. Dobbiamo utilizzare, perciò, un altro approccio.

Il primo passo è quello di modificare il bootstrapper, per trasformare l’oggetto di tipo PhoneContainer (che viene utilizzata per registrare e risolvere le varie classi utilizzate nell’applicazione) in una proprietà pubblica:

public class Bootstrapper : PhoneBootstrapper 
{ 
    public  PhoneContainer container { get; set; } 
  
    protected override void Configure() 
    { 
        container = new PhoneContainer(RootFrame); 
  
        container.RegisterPhoneServices(); 
        container.PerRequest<MainPageViewModel>(); 
        AddCustomConventions(); 
    } 
  
    static void AddCustomConventions() 
    { 
        //ellided   
    } 
  
    protected override object GetInstance(Type service, string key) 
    { 
        return container.GetInstance(service, key); 
    } 
  
    protected override IEnumerable<object> GetAllInstances(Type service) 
    { 
        return container.GetAllInstances(service); 
    } 
  
    protected override void BuildUp(object instance) 
    { 
        container.BuildUp(instance); 
    } 
}

Dopodichè possiamo sfruttare questa proprietà per ottenere un riferimento alla classe EventAggregator nel costruttore del code behind della View:

private IEventAggregator eventAggregator; 
  
// Constructor 
public MainPage() 
{ 
    InitializeComponent(); 
  
    Bootstrapper bootstrapper = Application.Current.Resources["bootstrapper"] as Bootstrapper; 
  
    IEventAggregator eventAggregator = 
        bootstrapper.container.GetAllInstances(typeof (IEventAggregator)).FirstOrDefault() as IEventAggregator; 
  
    this.eventAggregator = eventAggregator; 
  
    eventAggregator.Subscribe(this); 
}

Come prima cosa otteniamo un riferimento al boostrapper: dato che è dichiarato come risorsa globale dell’applicazione, possiamo usare la collezione Application.Current.Resources.

Dopodichè recuperiamo tutte gli oggetti di tipo IEventAggregator registrati nel container, tramite il metodo GetAllInstances(): dato che ne viene registrata solamente una istanza, recuperiamo solamente il primo risultato tramite l’operazione LINQ FirstOrDefault(). Infine, esattamente come facevamo nel ViewModel, chiamiamo il metodo Subscribe() della classe EventAggregator, passando this come parametro per abilitare la ricezione di messaggi nella pagina stessa.

A questo punto siamo in grado, anche nel code behind della View, di implementare l’interfaccia IHandle<T> e quindi implementare il metodo Handle(), all’interno del quale gestiremo il messaggio:

public partial class MainPage : PhoneApplicationPage, IHandle<SampleMessage> 
{ 
    private IEventAggregator eventAggregator; 
  
    // Constructor 
    public MainPage() 
    { 
        InitializeComponent(); 
  
        Bootstrapper bootstrapper = Application.Current.Resources["bootstrapper"] as Bootstrapper; 
  
        IEventAggregator eventAggregator = 
            bootstrapper.container.GetAllInstances(typeof (IEventAggregator)).FirstOrDefault() as IEventAggregator; 
  
        this.eventAggregator = eventAggregator; 
  
        eventAggregator.Subscribe(this); 
    } 
  
    public void Handle(SampleMessage message) 
    { 
        MessageBox.Show(message.Name); 
    }  
}

Se, invece, volessimo spedire un messaggio dal code behind è sufficiente chiamare il metodo Publish() della classe EventAggregator passando l’istanza del messaggio:

public partial class MainPage : PhoneApplicationPage 
{ 
    private IEventAggregator eventAggregator; 
  
    // Constructor 
    public MainPage() 
    { 
        InitializeComponent(); 
  
        Bootstrapper bootstrapper = Application.Current.Resources["bootstrapper"] as Bootstrapper; 
  
        IEventAggregator eventAggregator = 
            bootstrapper.container.GetAllInstances(typeof (IEventAggregator)).FirstOrDefault() as IEventAggregator; 
  
        this.eventAggregator = eventAggregator; 
  
        eventAggregator.Subscribe(this); 
    } 
  
    private void OnSendOtherMessageClicked(object sender, RoutedEventArgs e) 
    { 
        eventAggregator.Publish(new SampleMessage("Matteo")); 
    } 
}

In questo esempio, alla pressione di un pulsante nell’interfaccia, viene inviato un nuovo messaggio di tipo SampleMessage. Ovviamente, si tratta solamente di un esempio e non di uno scenario reale: in un’applicazione vera avremmo associato l’azione del pulsante ad un comando nel ViewModel tramite l’apposita convenzione.

Siamo giunti al termine di questo post: non siamo ancora però giunti alla fine, sono ancora tanti gli argomenti da affrontare relativi a Caliburn Micro. Nel frattempo, potete sperimentare con il progetto di esempio allegato.


Windows Phone , Caliburn , MVVM

1 comments

Sviluppare applicazioni per Windows Phone 8: presto in libreria!

Print Content | More

Come avrete notato negli ultimi mesi non sono riuscito a mantenere il mio blog aggiornato con la solita costanza. Finalmente posso svelarne il motivo: stavo scrivendo un libro Smile Nel mercato italiano mancava ancora una guida dedicata allo sviluppo di applicazioni per Windows Phone 8: ecco perciò che, grazie alla collaborazione con il blog Windows Phone Magazine Italia e con Nokia, è nata l’opportunità di scrivere questa guida, che vuole raccogliere un po’ l’esperienza che ho accumulato in questi anni e fornire uno strumento che affronti le tematiche di sviluppo dalla A alla Z e che possa essere adatto sia ai neofiti sia a chi ha già un po’ di esperienza e vuole approfondire le novità della nuova versione.

Nel corso delle 650 e passa pagine che compongono il volume si verrà gradualmente introdotti alle basi (lo XAML, la creazione del primo progetto, il ciclo di vita delle applicazioni) per poi affrontare argomenti più complessi e che consentiranno di mettere in pratica la vostra creatività e fantasia (le Speech API, NFC, le live tile, ecc.)

Il librò sarà disponibile indicativamente per fine Aprile / inizio Maggio in libreria, come e-book e presso i principali distributori online, come Amazon, e sarà pubblicato dalla casa editrice Edizioni Fag Milano: mi fa molto piacere segnalare, inoltre, che il libro contiene una prefazione a cura di Marco Argenti, Senior Vice President della Developer Division di Nokia World.

E’ stato un lavoro impegnativo (soprattutto considerando che ho un lavoro regolare e quindi questo libro è frutto del mio tempo libero), ma ricco di soddisfazioni: spero che chi di voi lo acquisterà lo trovi interessante tanto quanto è stato piacevole per me scriverlo!

Sarà mia premura tenervi aggiornati, attraverso questo blog, sulla disponibilità e sul prezzo finale una volta che mi saranno comunicati.

image


Windows Phone

4 comments

Caliburn Micro e Windows Phone – Navigazione avanzata e deep link

Print Content | More

In uno dei post precedenti abbiamo visto come gestire la navigazione in un’applicazione sviluppata con il pattern MVVM sfruttando le funzionalità di Caliburn Micro. In qesto post approfondiremo l’argomento, trattando una serie di scenari più avanzati, come la gestione degli eventi navigazione e il supporto ai deep link, uno dei meccanismi più utilizzati dalle API di Windows Phone per il passaggio di parametri.

Deep link

Windows Phone ha sempre supportato, sin dalla prima versione, la possibilità di passare parametri da una pagina all’altra tramite le query string che vengono aggiunte all’url di navigazione. Windows Phone 7.5 ha introdotto il concetto di deep link, ovvero la possibilità di sfruttare lo stesso meccanismo anche dall’esterno: il sistema operativo è in grado di aprire un’applicazione specificando sia la pagina a cui portare direttamente l’utente, sia eventuali parametri che aiutino lo sviluppatore a identificare il contesto della richiesta.

Ci sono tanti esempi di questo meccanismo: quando creiamo una tile secondaria, utilizziamo un deep link per identificare quale tile è stata selezionata; quando inviamo una notifica toast siamo in grado di specificare un deep link, per gestire il tap dell’utente sulla stessa; le nuove API di Windows Phone 8 per il supporto ai comandi vocali usano un deep link per passare all’applicazione il comando pronunciato dall’utente.

In condizioni normali, intercettare questa informazione in un’applicazone sviluppata utilizzando il pattern MVVM non è banale, dato che comporta due passaggi:

  • Intercettare l’evento OnNavigatedTo(), che viene scatenato quando l’utente viene portato alla pagina corrente;
  • Utilizzare la classe NavigationContext per accedere all’url di navigazione e ai relativi parametri in query string.

Purtroppo, però, sono API che sono accessibili solamente dal code behind di una View, in quanto eredita dalla classe PhoneApplicationPage.

Fortunatamente Caliburn Micro espone una convenzione molto semplice per gestire per noi questo scenario: è sufficiente dichiarare una proprietà nel ViewModel con lo stesso nome del parametro in query string; Caliburn Micro si occuperà di iniettare automaticamente, in tale proprietà, il valore recuperato dal parametro in query string.

Proviamo a implementare questo meccanismo utilizzando un’applicazione standard che faccia uso di Caliburn Micro: definiamo una View e un ViewModel e colleghiamoli utilizzando la convenzione standard, dopodichè nello XAML aggiungiamo un pulsante per creare una tile secondaria e un controllo TextBlock per mostrare il valore recuperato dalla query string:

<StackPanel>
    <TextBlock Text="{Binding Name}" />
    <Button Content="Create secondary tile" x:Name="CreateTile" />
</StackPanel>

Ecco, invece, il relativo ViewModel:

public class MainPageViewModel: PropertyChangedBase
{
    private string name;
 
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyOfPropertyChange(() => Name);
        }
    }
 
    public void CreateTile()
    {
                    ShellTileData tile = new StandardTileData
                                     {
                                         Title = "Test",
                                     };
 
            ShellTile.Create(new Uri("/Views/MainPage.xaml?Name=Matteo", UriKind.Relative), tile);
    }
 
}

Nel ViewModel abbiamo definito una proprietà di nome Name che, grazie all’utilizzo della convenzione di Caliburn, sarà mostrata all’interno del controllo TextBlock. Sempre utilizzando le onvenzioni, facciamo sì che alla pressione del pulsante venga eseguito il metodo CreateTile(), il quale si occupa di creare una nuova tile secondaria valorizzandone semplicemente il titolo. Potete notare che, nella creazione della tile, passiamo un deep link che contiene un parametro di nome Name.

Ora lanciate l’applicazione e premete il pulsante per creare la tile secondaria: l’applicazione sarà chiusa, per mostrare direttamente la nuova tile nella home. Fateci tap sopra e.. voilà! Il valore del parametro Name (ovvero Matteo) sarò visualizzato all’interno del controllo TextBlock, grazie alla convenzione di Caliburn.

Intercettare gli eventi di navigazione

Spesso abbiamo la necessità di intercettare gli eventi che il runtime ci mette a disposizione per capire quando l’utente si sta spostando da e verso una pagina. Ad esempio, se vogliamo che i dati della nostra pagina siano ricaricati ogni volta che l’utente ci arriva, non possiamo affidarci al costruttore del ViewModel, perchè questi viene inizializzato solo la prima volta che la pagina viene richiesta (pensiamo ad esempio alla pagina principale che, essendo la prima, rimane sempre in vita fino a che l’applicazione non viene chiusa).

Così come ho ricordato all’inizio del post, si tratta di uno scenario complesso da gestire in un’applicazione che fa uso di MVVM, data che gli eventi OnNavigatedTo() e OnNavigatedFrom() non sono accessibili dal ViewModel. A questo scopo, Caliburn Micro mette a disposizione una classe da utilizzare all’interno dei ViewModel, che permette di agganciarsi agli stessi eventi a cui normalmente siamo in grado di accedere solamente dal code behind. La classe si chiama Screen e, per utilizzarla, è sufficiente far ereditare il ViewModel dalla stessa.

La classe Screen implementa una serie piuttoto nutrita di intefacce, che ci permettono di gestire gli eventi di navigazione, come ViewAware, IActivate e IDeactivated:

public class Screen : ViewAware, IScreen, IHaveDisplayName, IActivate, IDeactivate, IGuardClose, IClose, INotifyPropertyChangedEx, INotifyPropertyChanged, IChild
{
 
}

In più, come potete vedere, la classe Screen implementa anche l’interfaccia INotifyPropertyChanged, di conseguenza non abbiamo la necessità di far ereditare il nostro ViewModel anche dalla classe PropertyChangedBase, avremo comunque accesso all’evento NotifyOfPropertyChange(), indispensabile per supportare il binding.

Una volta che il ViewModel è opportunamente configurato, possiamo fare l’override di una serie di metodi per gestire i vari eventi di navigazione:

public class MainPageViewModel: Screen
{
    protected override void OnViewAttached(object view, object context)
    {
        base.OnViewAttached(view, context);
        Debug.WriteLine("OnViewAttached");
    }
 
    protected override void OnInitialize()
    {
        base.OnInitialize();
        Debug.WriteLine("OnInitialize");
    }
 
    protected override void OnViewReady(object view)
    {
        base.OnViewReady(view);
        Debug.WriteLine("OnViewReady");
    }
 
    protected override void OnActivate()
    {
        base.OnActivate();
        Debug.WriteLine("OnActivate:");
    }
 
    protected override void OnViewLoaded(object view)
    {
        base.OnViewLoaded(view);
        Debug.WriteLine("OnViewLoaded");
    }
 
    protected override void OnDeactivate(bool close)
    {
        base.OnDeactivate(close);
        Debug.WriteLine("OnDeactivate");
    }
}

Ecco una descrizione dei vari metodi disponibili:

  • OnViewAttached() viene eseguito nel momento in cui il ViewModel viene impostato come DataContext della View;
  • OnInitialize() viene eseguito quando la View viene caricata;
  • OnViewReady() viene eseguito quando la View è pronta per essere visualizzata;
  • OnViewLoaded() è chiamato quando la View è stata completamente caricata e tutti i controlli sono stati inizializati;
  • OnActivate() è chiamato quando la View viene visualizzata;
  • OnDeactivate() è chiamato ogni qualvolta ci spostiamo dalla View corrente;

I due eventi più importanti sono OnActivate() e OnDeactivate(), che corrispondono a OnNavigatedTo() e OnNavigatedFrom() esposti dalla pagina: potete utilizzarli per gestire operazioni che non possono essere automatizzate tramite gli helper e le convenzioni di Caliburn Micro.

Nello specifico, l’evento OnActivate() è molto importante perchè viene scatenato quando la View è stata completamente caricata e siete in grado di interagire con la stessa: ad esempio, tale evento può essere utilizzato per caricare i dati da mostrare all’interno della View. Pensate al tipico approccio nella definizione di un ViewModel: tipicamente si gestisce, nel costruttore del ViewModel, il caricamento dei dati. Questo approccio ha però un limite, evidente soprattutto al giorno d’oggi con l’introduzione delle parole chiave async e await per gestire le operazioni asincrone. Il costruttore di una classe, infatti, non può essere asincrono. Solitamente si usa l’approccio di demandare l’operazione di caricamento ad un altro metodo, che viene invocato nel costruttore:

public MainPageViewModel()
{
    LoadData();
}
 
private async void LoadData()
{
    MyData = await service.LoadData();
}

Qual è il problema di questa soluzione? Che il metodo LoadData() deve essere di tipo void, non può ritornare un Task dato che nel costruttore del ViewModel non possiamo usare la parola chiave await. Il problema è che, in questo metodo, il metodo LoadData() è di tipo “fire and forget”: eseguiamo l’operazione e non aspettiamo che questa sia terminata. In più, non siamo in grado di catturare eventuali eccezioni. Nella maggior parte dei casi questo approccio funzionerà comunque, soprattutto se i dati da caricare non sono molti: prima che l’utente inizi ad interagire con l’interfaccia, i dati saranno probabilmente già pronti per essere consumati.

Un approccio più efficiente è quello di sfruttare gli eventi di navigazione, spostando il caricamento dei dati all’interno del metodo OnActivate():

public MainPageViewModel()
{
 
}
 
protected override async void OnActivate()
{
    MyData = await service.LoadData();
} 

In questo caso è corretto che il metodo OnActivate() sia di tipo void, perchè le operazioni di attivazione vengono gestite in automatico dal sistema operativo. E’ lo stesso tipo di approccio che, ad esempio, si utilizza con gli event handler che Visual Studio genera quando vogliamo gestire il click di un pulsante (o qualsiasi altro evento esposto da uno dei controlli nello XAML) da code behind.

Il metodo OnActivate() è molto importante anche per la gestione dei deep link che abbiamo visto in precedenza: infatti si può verificare che, quando il ViewModel viene creato e il costruttore della classe invocato, i parametri presenti in query string non siano ancora stati iniettati nelle corrispondenti proprietà.

Questo perchè l’evento OnNavigatedTo() della pagina, che viene sfruttato per recuperare i parametri e iniettarli nel ViewModel, si verifica dopo che il costruttore della classe è già stato eseguito. Nell’esempio che abbiamo fatto in precedenza non abbiamo avuto modo di accorgerci del problema grazie al binding e all’implementazione dell’interfaccia INotifyPropertyChanged: nel momento in cui Caliburn ha valorizzato le proprietà del ViewModel con i parametri in query string, grazie al binding il controllo TextBlock si è immediatamente aggiornato per mostrare il nuovo valore.

Avremmo potuto, invece, notare il problema se avessimo cercato di manipolare la proprietà Name all’interno del costruttore del ViewModel: in tal caso, ci saremmo accorti che la proprietà Name sarebbe stata uguale a null. Il codice seguente avrebbe perciò scatenato un’eccezione:

public class MainPageViewModel: PropertyChangedBase
{
    private string name;
 
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyOfPropertyChange(() => Name);
        }
    }
 
    public MainPageViewModel()
    {
        MessageBox.Show(Name);    
    }
 
}

La soluzione è quella di manipolare la proprietà Name all’interno dell’evento OnActivate(): in questo modo, ci assicuriamo che il lavoro di Caliburn sia stato completato e che la proprietà contenga effettivamente il valore del parametro contenuto all’interno del deep link. Ecco il codice corretto:

public class MainPageViewModel: Screen
{
    private string name;
 
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyOfPropertyChange(() => Name);
        }
    }
 
    public void OnActivate()
    {
        MessageBox.Show(Name);
    }
 
}

Come sempre, di seguito trovate il link per scaricare il progetto di esempio relativo a quanto appreso in questo post.


Windows Phone , MVVM , Caliburn

0 comments

Caliburn Micro e Windows Phone – Tombstoning

Print Content | More

Il tombstoning è la croce e la delizia di ogni sviluppatore. E’ fondamentale gestirlo perchè consente, anche in caso di terminazione dell’applicazione parte del sistema operativo, di dare l’illusione all’utente che, in realtà, l’applicazione non sia mai stato chiusa; non è così semplice, però, gestirlo correttamente, soprattutto in applicazioni sviluppate con il pattern MVVM, dato che tipicamente si sfruttano gli eventi di navigazione OnNavigatedFrom() per salvare lo stato della pagina e OnNavigatedTo() per recuperarlo. Se utilizziamo il pattern MVVM non abbiamo accesso diretto a questi eventi, dato che sono esposti solamente dal code behind della View.

Un approccio che mettono a disposizone molti framework per MVVM è l’utilizzo di helper che consentono di agganciarsi a questi eventi anche da un ViewModel. Anche Caliburn Micro mette a disposizione questa funzionalità, ma la vedremo in futuro perchè, per il tombstoning, utilizzeremo un altro approccio: creeremo un’altra classe, collegata al ViewModel, che ci permetterà di specificare il comportamento da adottare durante la fase di sospensione dell’applicazione.

Vediamone il funzionamento in dettaglio, creando un nuovo progetto Windows Phone sfruttando quanto abbiamo appreso nei post precedenti, così da avere una View collegata al relativo ViewModel.

Nello XAML della View inseriamo un controllo TextBox, che collegheremo ad una proprietà nel ViewModel utilizzando la convenzione che abbiamo imparato a conoscere:

<TextBox x:Name="Name" />

Dopdichè definiamo nel ViewModel una proprietà con lo stesso nome, ovvero Name:

public class MainPageViewModel: PropertyChangedBase
{
    private string name;
 
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyOfPropertyChange(() => Name);
        }
    }
}

Prima di impplementare il supporto al tombstoning facciamo un semplice test: lanciamo l’applicazione, scriviamo qualcosa all’interno del controllo TextBox e poi premiamo il pulsante Start per sospenderla. Ora premete il pulsante Back per tornare all’applicazione: il testo che avete inserirò sarà ancora lì. Questo perchè, come comportamento predefinito, le applicazioni vengono mandate in stato dormant: il processo non è attivo, ma è comunque mantenuto in memoria, perciò non c’è bisogno di recuperarlo manualmente.

Ora proviamo a simulare il tombstoning, grazie a Visual Studio: le applicazioni vengono mandate, di default, in stato dormant; lo stato tombstoned viene utilizzato solo quando il sistema sta esaurendo la memoria e quindi inizia a terminare le applicazioni più vecchie per lasciare spazio a quelle nuove. Dato che si tratta di uno scenaro non deterministico (non siamo in grado di sapere, a priori, quando l’applicazione sarà terminata) Visual Studio mette a disposizione la possibilità di simulare il tombstoning: dobbiamo fare clic con il tasto destro sul progetto e, nella sezione Debug, abilitare la voce Tombstone upon activation while debugging. Abilitatelo e ripetete il test precedente: noterete che, questa volta, al momento della riattivazone il testo sarà sparito.

Questo è lo scenario che dobbiamo gestire: in fase di sospensione dobbiamo salvare il contenuto del testo e, in fase di attivazione, recuperarlo e riassegnarlo al controllo TextBox. Per sfruttare gli helper di Caliburn Micro dobbiamo creare una nuova classe, che deve ereditare da StorageHandler<T>, dove T è il ViewModel che contiene i dati da salvare. Ecco un esempio:

public class MainPageModelStorage: StorageHandler<MainPageViewModel>
{
    public override void Configure()
    {
        Property(x => x.Name)
            .InPhoneState();
    }
}

L’utilizzo della classe StorageHandler<T> richiede l’implementazione del metodo Configure(), che “contiene” le istruzioni su come l’applicazione si deve comportare nel momento in cui viene sospesa. Utilizziamo il metodo Property(), passando come parametro (tramite una lambda expression), la proprietà del ViewModel che vogliamo salvare. Ci viene in aiuto l’IntelliSense di Visual Studio: dato che la proprietà x contenuta all’interno della lambda expression coincide con il ViewModel specificato come tipo della classe StorageHandler , saremo in grado di vedere tutte le proprietà incluse nel ViewModel. L’ultimo passaggio è specificare dove vogliamo salvare i dati: utilizzando il metodo InPhoneState() la proprietà viene salvato nella memoria temporanea dell’applicazione, che viene svuotata nel momento in cui questa viene chiusa o riaperta utilizzando la tile principale e non riattivata da una sospensionne.

E’ la soluzione ideale per il nostro scenario: ipotizzando che il controllo TextBox faccia parte di un form più complesso, è corretto mantenerne lo stato da una sospensione all’altra, mentre non è indispensabile farlo nel momento in cui l’utente decide di riaprire l’applicazione dall’inizio. Nel caso, invece, vogliate mantenerne lo stato anche in caso di chiusura dell’applicazione è disponibile il metodo InAppSettings(), come nell’esempio:

public class MainPageModelStorage: StorageHandler<MainPageViewModel>
{
    public override void Configure()
    {
        Property(x => x.Name)
            .InAppSettings();
    }
}

Ora possiamo fare qualche esperimento avviando l’applicazione e salvando i dati usando il metodo InPhoneState(): assicuriamoci che, tra le proprietà del progetto, sia ancora attiva l’opzione che forza il tomstoning, scriviamo qualcosa nel controllo TextBox, sospendiamo l’applicazione e riapriamola. Nonostante il processo sia stato terminato, il testo sarà ancora lì: la classe MainPageModelStorage si è fatta carico di salvare e recuperare lo stato della proprietà nel ViewModel associata al controllo TextBox. Se invece chiudiamo l’applicazione con il pulsante Back e la riapriamo non troveremo più il testo che avevamo inserito: è corretto, dato che abbiamo utilizzato il metodo InPhoneState(). Se lo sostituiamo al metodo InAppSettings(), invece, vedremo il contenuto del controllo TextBlock rimanere al suo posto anche in caso di chiusura dell’applicazione.

Nel prossimo post

Non abbiamo ancora finito di esplorare le caratteristiche di Caliburn Micro. Nel frattempo, potete scaricare un progetto di esempio per fare esperimenti con quanto appreso in questo post.


Windows Phone , MVVM , Caliburn

0 comments