我有ListView
绑定到ObservableCollection
。此ListView使用ItemTemplate,它只包含一个Image
控件,Source属性绑定到URL字符串。
对于某些网址图片无法加载,因为远程服务器会返回“禁止(403)” - 可以通过向获取图像的HTTP请求添加特定标头来解决此 ,但是问题是我不知道应该如何修改上述请求。
我尝试了两种不同的方法:
IValueConverter
对象。我会自己获取URL并获取图像数据 - 将其放入MemoryStream
并使用该流初始化BitmapImage
对象并将其返回到Image控件。事实证明这种方法非常慢,并且阻止了UI线程。PropertyChanged
事件,以便在视觉上更新图像。这种方法没有阻止UI线程,但由于某种原因它非常慢。我想知道两件事:
为什么我的方法明显变慢了?
如何直接修改Image控件从远程服务器获取图像的方式而不会影响性能/速度那么多?
考虑以下示例:
public byte[] ImageThumbnail
{
get
{
if (img == null) img = GetImage(ImageUrls.Thumbnail);
return img;
}
}
public byte[] GetImage(string url) {
HttpClient client = new HttpClient();
// add some headers
return client.GetByteArrayAsync(url).Result;
}
将IsAsync设置为True,将图像绑定到“ImageThumbnail”。与仅将URL直接绑定到Image源相比,在这种情况下,图像的下载速度要慢得多。
答案 0 :(得分:0)
您应该在ItemTemplate中对Image控件的Source
属性使用异步绑定:
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Image, IsAsync=True}"/>
</DataTemplate>
</ListBox.ItemTemplate>
由于现在在后台线程中调用Image
属性getter,因此必须通过冻结使返回的ImageSource可以跨线程访问。
public class ImageItem
{
private string url;
public ImageItem(string url)
{
this.url = url;
}
public ImageSource Image
{
get
{
var image = new BitmapImage();
var buffer = new WebClient().DownloadData(url);
using (var stream = new MemoryStream(buffer))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
image.Freeze();
return image;
}
}
}
使用BitmapFrame
代替BitmapImage
可能会缩短Image属性。下面显示的BitmapFrame.Create
方法已经返回了一个冻结的BitmapFrame。
public ImageSource Image
{
get
{
var buffer = new WebClient().DownloadData(url);
using (var stream = new MemoryStream(buffer))
{
return BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
}