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;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…