Make WPF Image load async

I would like to download Gravatar-Images and install them from code in WPF Image-Control. So the code looks like

imgGravatar.Source = GetGravatarImage(email); 

Where GetGravatarImage looks like this:

 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; 

Unfortunately, this blocks the GUI on a slow network connection. Is there a way to assign an image source and let it load an image in the background without blocking the user interface?

Thanks!

+7
source share
3 answers

I suggest you use the binding on your imgGravatar from XAML. Set IsAsync = true , and WPF automatically uses the thread from the thread pool to pull your image. You can encapsulate resolving logic in IValueConverter and just bind it as a source

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 code:

 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; } } } 
+19
source

I don’t understand why your code is blocking the user interface since BitmapImage supports loading image data in the background. Therefore, it has the IsDownloading and DownloadCompleted property.

In any case, the following code shows an easy way to download and create an entire image in a separate thread (from ThreadPool ). It uses an instance of WebClient to load the entire image buffer before creating a BitmapImage from this buffer. After creating BitmapImage, it calls Freeze to make it accessible from the user interface thread. Finally, it assigns the Source image control property to the UI thread by calling 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)); }); 
+6
source

You can take a look at this question:

Link

And I would recommend running the Asynchrone task and putting code that should be asynchronous in this task.

0
source

All Articles