2017-05-16 41 views
0

我有一個ListView綁定到ObservableCollection。此ListView使用ItemTemplate,其中只包含一個Image控件,該Source屬性綁定到URL字符串。WPF圖像 - 服務器返回禁止(403)

對於一些網址圖像加載失敗,因爲遠程服務器將返回「禁止(403)」 - 這可以加入一定頭到獲取圖像的HTTP請求來解決,但問題是我不我不知道如何去修改這個請求。

我嘗試了兩種不同的方法:

  1. 創建IValueConverter對象。我會自己取URL並獲取圖像數據 - 將其放入MemoryStream,並使用該流初始化一個BitmapImage對象並將其返回給Image控件。這種方法被證明非常慢,並且阻塞了UI線程。
  2. 創建一個綁定到該屬性的新屬性將返回一個包含圖像數據的字節數組。這些數據在第一次使用Task調用時會被懶惰地初始化。當數據完成下載時,將觸發PropertyChanged事件,以便可視化地更新Image。這種方法並沒有阻止UI線程,但由於某種原因速度非常慢。

我想知道兩件事情:

  • 爲什麼是我的方法顯著慢?

  • 如何如何直接修改圖像控件從遠程服務器獲取圖像的方式,而不會影響性能/速度?

請看下面的例子:

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; 
} 

圖像將被綁定到 「ImageThumbnail」 與IsAsync設置爲True。與僅將URL直接綁定到Image源相比,在這種情況下圖像下載速度明顯較慢。

+0

「爲什麼我的方法明顯變慢?」除非您向我們展示您的代碼,否則沒有人會說出來。作爲提示,您應該使用異步綁定(通過設置其IsAsync屬性)。當綁定調用屬性getter時,直接綁定到創建的(異步)ImageSource屬性。不要使用綁定轉換器,因爲它不會被異步調用。 – Clemens

+0

是的,我想過爲什麼綁定轉換器不起作用,只是認爲可能存在異步實現方式。我已經嘗試過使用異步綁定 - 我已經爲該問題添加了一個示例。 – CryShana

回答

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; 
     } 
    } 
} 

Image屬性可能會寫入使用BitmapFrame,而不是BitmapImage有點短。下面顯示的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); 
     } 
    } 
} 
+0

這工作得很好。是因爲你直接返回一個凍結的ImageSource而不是一個字節數組? – CryShana

+1

是的。當你返回一個字節數組時,自動轉換爲ImageSource(即創建一個BitmapFrame)仍然在UI線程中發生。這裏介紹的解決方案儘可能在後臺線程中做到。 – Clemens

相關問題