2013-04-16 12 views
7

Vorrei caricare Gravatar-Images e impostarle da codice dietro a un Image Control di WPF. Così il codice è simileEffettua il caricamento dell'immagine WPF asincrono

imgGravatar.Source = GetGravatarImage(email); 

Dove GetGravatarImage assomiglia:

BitmapImage bi = new BitmapImage(); 
bi.BeginInit(); 
bi.UriSource = new Uri(GravatarImage.GetURL("http://www.gravatar.com/avatar.php?gravatar_id=" + email) , UriKind.Absolute); 
bi.EndInit(); 
return bi; 

Purtroppo questo blocca la GUI quando la connessione di rete è lenta. C'è un modo per assegnare l'origine dell'immagine e lasciar caricare l'immagine sullo sfondo senza bloccare l'interfaccia utente?

Grazie!

risposta

0

Si potrebbe voler dare un'occhiata a questa domanda:

Link

e consiglio per l'avvio di un'attività asynchrone, e mettere il codice che deve essere asincrona in questo compito.

19

Ti suggerisco di utilizzare una rilegatura sul tuo imgGravatar di XAML. Impostare IsAsync = true su di esso e WPF utilizzerà automaticamente una discussione dal pool di thread per estrarre l'immagine. Si potrebbe incapsulare la logica di risolvere in un IValueConverter e semplicemente legare l'e-mail come sorgente

in XAML:

<Window.Resouces> 
    <local:ImgConverter x:Key="imgConverter" /> 
</Window.Resource> 

... 


<Image x:Name="imgGravatar" 
     Source="{Binding Path=Email, 
         Converter={StaticResource imgConverter}, 
         IsAsync=true}" /> 

in Codice:

public class ImgConverter : IValueConverter 
{ 
    public override object Convert(object value, ...) 
    { 
     if (value != null) 
     { 
      BitmapImage bi = new BitmapImage(); 
      bi.BeginInit(); 
      bi.UriSource = new Uri( 
       GravatarImage.GetURL(
        "http://www.gravatar.com/avatar.php?gravatar_id=" + 
         value.ToString()) , UriKind.Absolute 
       ); 
      bi.EndInit(); 
      return bi;     
     } 
     else 
     { 
      return null; 
     } 

    } 
} 
+1

BitmapImage ha anche un [costruttore con il parametro Uri] (http://msdn.microsoft.com/en-us/library/ms602473.aspx), che si salverebbe le chiamate/EndInit BeginInit. – Clemens

+0

+1 non lo sapevo, bel suggerimento. Ho appena copiato il codice dall'autore e non ho pensato a come ottimizzare il download effettivo, invece mi sono concentrato sulla risoluzione del problema del blocco dell'interfaccia utente in modo elegante (e ovviamente blocca, se il codice non è asincrono). Penso che per l'uso ripetitivo, il convertitore potrebbe anche ottenere l'URL completo dall'associazione per essere più riutilizzabile, anziché l'e-mail. Non mi piace usare 'ThreadPool' perché devi gestire l'invio tutto il tempo. Questo non lo rende abbastanza elegante per una pura applicazione MVVM. – JanW

+0

Puoi fornire una spiegazione sul perché la creazione di un BitmapImage si blocchi quando non viene chiamata in modo asincrono. Perché allora ha la proprietà 'IsDownloading' e l'evento' DownloadCompleted'. Se si imposta semplicemente la proprietà 'Origine' di controllo immagine in XAML su un URL che fa riferimento a un'immagine grande sul Web, l'interfaccia utente non verrà bloccata. Invece, WPF scarica l'immagine in background e la mostra non appena il download è terminato. – Clemens

6

non riesco a capire perché il codice avrebbe bloccato l'interfaccia utente, poiché BitmapImage supporta il download dei dati dell'immagine in background. Ecco perché ha una proprietà IsDownloading e un evento DownloadCompleted.

In ogni caso, il codice seguente mostra un modo semplice per scaricare e creare l'immagine interamente in un thread separato (da ThreadPool). Utilizza un'istanza WebClient per scaricare l'intero buffer di immagini, prima di creare un BitmapImage da quel buffer. Dopo aver creato BitmapImage, chiama Freeze per renderlo accessibile dal thread dell'interfaccia utente. Infine assegna la proprietà Source del controllo immagine nel thread dell'interfaccia utente tramite una chiamata Dispatcher.BeginInvoke.

ThreadPool.QueueUserWorkItem(
    o => 
    { 
     var webClient = new WebClient(); 
     var url = GravatarImage.GetURL("http://www.gravatar.com/avatar.php?gravatar_id=" + email); 
     var buffer = webClient.DownloadData(url); 
     var bitmapImage = new BitmapImage(); 

     using (var stream = new MemoryStream(buffer)) 
     { 
      bitmapImage.BeginInit(); 
      bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
      bitmapImage.StreamSource = stream; 
      bitmapImage.EndInit(); 
      bitmapImage.Freeze(); 
     } 

     Dispatcher.BeginInvoke((Action)(() => image.Source = bitmapImage)); 
    }); 
Problemi correlati