我以幾種方式解決了這個問題,包括WebClient和BitmapImage。
編輯:最初的建議是使用BitmapImage(Uri, RequestCachePolicy)的構造函數,但我意識到我的項目,我測試這種方法只使用本地文件,而不是網絡。改變指導以使用我的其他測試網絡技術。
您應該在後臺線程上運行下載和解碼,因爲在加載過程中,無論是同步還是下載圖像後,解碼圖像都需要很短的時間。如果您正在加載許多圖像,這可能導致UI線程停頓。 (這裏還有其他一些複雜的問題,如DelayCreation,但它們不適用於您的問題。)
有幾種方法可以加載圖像,但我發現在BackgroundWorker中從網絡加載時,您需要使用WebClient或類似的類自行下載數據。
請注意,BitmapImage在內部使用WebClient,另外它還有很多錯誤處理和憑證設置以及其他我們必須針對不同情況設置的其他事項。我提供了這個片段,但它只在有限的幾種情況下進行了測試。如果您正在處理代理,憑證或其他場景,您將不得不對此進行一些處理。
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Uri uri = e.Argument as Uri;
using (WebClient webClient = new WebClient())
{
webClient.Proxy = null; //avoids dynamic proxy discovery delay
webClient.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
try
{
byte[] imageBytes = null;
imageBytes = webClient.DownloadData(uri);
if (imageBytes == null)
{
e.Result = null;
return;
}
MemoryStream imageStream = new MemoryStream(imageBytes);
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = imageStream;
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
image.Freeze();
imageStream.Close();
e.Result = image;
}
catch (WebException ex)
{
//do something to report the exception
e.Result = ex;
}
}
};
worker.RunWorkerCompleted += (s, e) =>
{
BitmapImage bitmapImage = e.Result as BitmapImage;
if (bitmapImage != null)
{
myImage.Source = bitmapImage;
}
worker.Dispose();
};
worker.RunWorkerAsync(imageUri);
我測試了這個在一個簡單的項目,它工作正常。我並不是100%關於它是否打到緩存,而是從MSDN可以告訴我的其他論壇問題,以及Reflectoring into PresentationCore中,它應該打到緩存。 WebClient包裝了WebRequest,它封裝了HTTPWebRequest等等,並且緩存設置在每一層傳遞。
BitmapImage BeginInit/EndInit對確保您可以同時設置所需的設置,然後在執行EndInit期間設置。如果你需要設置任何其他屬性,你應該使用空的構造函數,並寫出如上所示的BeginInit/EndInit對,在調用EndInit之前設置你需要的。
我通常還會設置這個選項,這迫使它EndInit期間將圖像加載到內存中:
image.CacheOption = BitmapCacheOption.OnLoad;
這將權衡可能的更高的內存使用情況更好的運行時性能。如果你這樣做,那麼BitmapImage將在EndInit中同步加載,除非BitmapImage需要從URL下載異步。
其它注意事項:
的BitmapImage將異步下載,如果UriSource是絕對URI是HTTP或HTTPS方案。您可以通過在EndInit之後檢查BitmapImage.IsDownloading屬性來判斷它是否正在下載。有DownloadCompleted,DownloadFailed和DownloadProgress事件,但你必須特別棘手才能讓它們在後臺線程中觸發。由於BitmapImage只公開了一種異步方法,因此您必須添加一個while循環與WPF等效的DoEvents()以使線程保持活動狀態,直到下載完成。爲的DoEvents,在這個片段中工作This thread顯示代碼:
worker.DoWork += (s, e) =>
{
Uri uri = e.Argument as Uri;
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = uri;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
image.EndInit();
while (image.IsDownloading)
{
DoEvents(); //Method from thread linked above
}
image.Freeze();
e.Result = image;
};
雖然上述方法工作,它有一個代碼味道,因爲的DoEvents()的,它不會讓你配置Web客戶端代理或其他東西,可能有助於提高性能。上面的第一個例子推薦使用這個例子。
您可以發佈您的BackgroundWorker代碼? – Rusty 2011-03-26 00:05:46