Multithreading in Silverlight 2.0
di Cristian Civera, in Silverlight 2.0, 3 febbraio 2009
4 pagine in totale: <<Indietro 1 2 [3] 4 Avanti >>
Interazione con l'interfaccia
Quanto visto fino adesso nasconde in realtà un piccolo problema, poiché è molto probabile che al termine di un'operazione asincrona si debba poi notificare l'utente o mostrare i risultati. Purtroppo ogni operazione che coinvolge un controllo di Silverlight va eseguita sul thread UI, infatti ogni tentativo genererebbe a runtime una UnauthorizedAccessException.
Fortunatamente la classe DependecyObject, tipo base per tutti gli elementi e controlli, espone la proprietà Dispatcher che restituisce l'omonimo tipo che dispone del metodo BeginInvoke il quale permette di accodare un delegate da eseguire sulla coda principale, insieme agli eventi e alle operazioni di disegno. Il nome BeginInvoke sta ad indicare che l'operazione viene accodata, ma il controllo viene subito restituito al Thread chiamante, perciò non è possibile controllare quando verrà poi eseguito il delegate.
Ecco quindi un esempio per cambiare una TextBlock da un Thread secondario:
void OnThreadPool(object state) { this.Dispatcher.BeginInvoke(OperationCompleted); } void OperationCompleted() { resultTextBlock.Text = "Finito"; }
Ovviamente valgono tutte le tecniche per creare passare un delegate a BeginInvoke: anonymous method o lambda expression.
this.Dispatcher.BeginInvoke(() => resultTextBlock.Text = "Finito");
Oppure
this.Dispatcher.BeginInvoke( delegate() { resultTextBlock.Text = "Finito"; });
Per facilitare questa frequente operazione, in Silverlight è presente la classe AsyncOperationManager con un unico metodo statico CreateOperation. La funzione restituisce un oggetto AsyncOperation che rappresenta un'operazione e contiene il metodo Post. Il delegate che ad esso si passa ha la particolarità di essere invocato sul Dispatcher, può essere invocato uno o più volte e si può terminare e rilasciare l'intera operazione con PostOperationCompleted o più semplicemente con OperationCompleted per rilasciare le risorse.
Ecco un esempio:
private void startOperation_Click(object sender, RoutedEventArgs e) { AsyncOperation operation = AsyncOperationManager.CreateOperation(null); ThreadPool.QueueUserWorkItem(OnThreadPool, operation); } void OnThreadPool(object state) { // Eseguito sul ThreadPool AsyncOperation operation = (AsyncOperation)state; // Notifico l'inizio dell'operazione operation.Post(ShowText, "Inizio operazione"); // Simulo l'operazione lunga Thread.Sleep(TimeSpan.FromSeconds(2)); // Notifico la fine dell'operazione operation.PostOperationCompleted(ShowText, "Fine operazione"); } void ShowText(object state) { // Eseguito sul Thread UI resultTextBlock.Text = (string)state; }
A prima vista, questa tecnica può sembrare poco vantaggiosa rispetto al semplice BeginInvoke del Dispatcher, ma in realtà permette di scrivere classi e componenti in modo indipendente dalla tecnologia Silverlight o dal classico .NET Framework (AsyncOperation è presente anche dal .NET Framework 2.0) oltre alla possibilità di poter effettuare unit testing su di essi, senza far funzionare l'intero motore.
Chiamante asincrone con la BCL di Silverlight
Quanto visto fino adesso permette di capire come i Thread funzionano e quali sono gli strumenti messi a disposizione in Silverlight. Nella maggior parte dei casi però, l'esecuzione di chiamate asincrone avviene su classi già incluse che, per i motivi indicati ad inizio articolo, implementano due diversi pattern e non vi è modo di poterle chiamare in modo sincrono, influenzando il thread UI.
Il primo pattern consiste in una serie di metodi che per convenzione sono chiamati [Operazione]Async con due overloads per passare facoltativamente un oggetto di stato, più un evento di nome [Operazione]Completed ed è utilizzato dalla classe WebClient (usata per effettuare chiamate HTTP) e dai proxy sui servizi creati da Visual Studio quando si esegue "Add service reference".
Il vantaggio di questo approccio unico risiede nel fatto che il metodo per avviare la chiamata asincrona rilascia subito il controllo al thread UI, mentre l'evento associato che sfrutta AsyncOperation, visto nel paragrafo precedente, viene invocato nuovamente sul thread UI. Tale evento contiene negli argomenti il risultato e permette di interagire facilmente con l'interfaccia senza preoccuparsi dei problemi di threading incontrati in precedenza.
Di seguito quindi un esempio per effettuare una chiamata HTTP ad una pagina internet sfruttando questo pattern:
void callHttp_Click(object sender, EventArgs e) { WebClient client = new WebClient(); // Intercetto l'evento per conoscere la fine dell'operazione client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); // Avvio la chiamata asincrona client.DownloadStringAsync(new Uri("http://www.aspitalia.com")); } void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { // Controllo che non si siano verificati errori // o che l'operazione non sia stata cancellata if (e.Error != null) resultTextBlock.Text = "Errore nell'esecuzione: " + e.Error.Message; else if (!e.Cancelled) resultTextBlock.Text = e.Result; }
Il pattern inoltre prevede che l'argomento passato all'evento erediti da AsyncCompletedEventArgs così da disporre sempre le proprietà Error, Cancelled e UserState per conoscere l'eventuale Exception, se è stata cancellata l'operazione (la classe WebClient ha un metodo CancelAsync) o l'oggetto di stato passato nella chiamata iniziale.
4 pagine in totale: <<Indietro 1 2 [3] 4 Avanti >>
Contenuti dell'articolo
Sullo stesso argomento
-
Applicazioni Silverlight con il cloud computing su Windows Azure
-
Aggiungere interattività al controllo Chart di Silverlight 3.0
-
Realizzare un sito completo in Silverlight: una galleria fotografica
-
Supporto audio e video in Silverlight 3.0
-
Effetti speciali sulle immagini in Silverlight 3.0
-
Anteprima di Expression Blend 3.0
-
Le novità di Silverlight 3.0 beta 1
-
Realizzare un menu riutilizzabile utilizzando DataTemplate e DataBinding
-
Un tocco di stile alle applicazioni Silverlight: style e template

















Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.