async load BitmapImage in C#

前端 未结 1 1932
面向向阳花
面向向阳花 2020-12-18 16:07

I\'m trying to load a image asynchronously.

MainWindow code

public partial class MainWindow : Window
{
    private Data data = new D         


        
相关标签:
1条回答
  • 2020-12-18 17:04

    When a BitmapImage is created in a background thread, you have to make sure that it gets frozen before it is used in the UI thread.

    You would have to load it yourself like this:

    public static async Task<BitmapImage> GetNewImageAsync(Uri uri)
    {
        BitmapImage bitmap = null;
        var httpClient = new HttpClient();
    
        using (var response = await httpClient.GetAsync(uri))
        {
            if (response.IsSuccessStatusCode)
            {
                using (var stream = new MemoryStream())
                {
                    await response.Content.CopyToAsync(stream);
                    stream.Seek(0, SeekOrigin.Begin);
    
                    bitmap = new BitmapImage();
                    bitmap.BeginInit();
                    bitmap.CacheOption = BitmapCacheOption.OnLoad;
                    bitmap.StreamSource = stream;
                    bitmap.EndInit();
                    bitmap.Freeze();
                }
            }
        }
    
        return bitmap;
    }
    

    Or shorter with BitmapFrame.Create, which returns an already frozen BitmapSource:

    public static async Task<BitmapSource> GetNewImageAsync(Uri uri)
    {
        BitmapSource bitmap = null;
        var httpClient = new HttpClient();
    
        using (var response = await httpClient.GetAsync(uri))
        {
            if (response.IsSuccessStatusCode)
            {
                using (var stream = new MemoryStream())
                {
                    await response.Content.CopyToAsync(stream);
                    stream.Seek(0, SeekOrigin.Begin);
    
                    bitmap = BitmapFrame.Create(
                        stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
                }
            }
        }
    
        return bitmap;
    }
    

    Note that the second method requires to change the type of your Image property to BitmapSource (or even better, ImageSource), which would provide greater flexibility anyway.


    An alternative method without any manual download might look like shown below. It also does not require to freeze the BitmatImage, because it is not created in a Task thread.

    public static Task<BitmapSource> GetNewImageAsync(Uri uri)
    {
        var tcs = new TaskCompletionSource<BitmapSource>();
        var bitmap = new BitmapImage(uri);
    
        if (bitmap.IsDownloading)
        {
            bitmap.DownloadCompleted += (s, e) => tcs.SetResult(bitmap);
            bitmap.DownloadFailed += (s, e) => tcs.SetException(e.ErrorException);
        }
        else
        {
            tcs.SetResult(bitmap);
        }
    
        return tcs.Task;
    }
    
    0 讨论(0)
提交回复
热议问题