我正在尝试异步加载图像。
主窗口代码
public partial class MainWindow : Window
{
private Data data = new Data();
public MainWindow()
{
InitializeComponent();
this.DataContext = data;
}
private async void button_Click(object sender, RoutedEventArgs e)
{
data.Image = await Data.GetNewImageAsync();
}
}
数据类
public class Data : INotifyPropertyChanged
{
private BitmapImage _Image = new BitmapImage();
public BitmapImage Image { get { return _Image; } set { _Image = value; OnPropertyChanged("Image"); } }
public static BitmapImage GetNewImage()
{
return new BitmapImage(new Uri("http://www.diseno-art.com/news_content/wp-content/uploads/2012/09/2013-Jaguar-F-Type-1.jpg"));
}
public async static Task<BitmapImage> GetNewImageAsync()
{
return await Task.Run(() => GetNewImage());
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
WPF代码
<Button Name="button" Click="button_Click">Image</Button>
<Image Grid.Row="1" Source="{Binding Path=Image, UpdateSourceTrigger=PropertyChanged}"></Image>
问题
我得到异常:
System.ArgumentException: "Must create DependencySource on same Thread as the DependencyObject."
...在这一行: PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
但是如果我将 BitmapImage 更改为字符串,则此代码可以正常工作。
我做错了什么?
请您参考如下方法:
当在后台线程中创建 BitmapImage 时,您必须确保在 UI 线程中使用它之前将其卡住。
你必须像这样自己加载它:
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;
}
或者使用 BitmapFrame.Create 更短,它返回一个已经卡住的 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;
}
请注意,第二种方法需要将 Image 属性的类型更改为 BitmapSource(或者更好的是 ImageSource),这无论如何都会提供更大的灵 active 。
无需任何手动下载的替代方法可能如下所示。它也不需要卡住 BitmatImage,因为它不是在任务线程中创建的。
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;
}
