Bu sorunu WebClient ve BitmapImage ile birlikte de dahil olmak üzere çeşitli şekillerde ele aldım.
DÜZENLEME: Orijinal öneri BitmapImage(Uri, RequestCachePolicy) yapıcı kullanmaktı, ama bu yöntem sadece yerel dosyalar, web değil kullanıyordum test projemi fark etti. Test edilen diğer web tekniğimi kullanmak için rehberlik değiştirme.
Sen görüntü, görüntü şifresini çözmek için gerekli küçük ama önemli zaman vardır senkron olsun veya indirildikten sonra, çünkü yükleme sırasında bir arka plan iş parçacığı üzerinde yükleme ve çözme çalışmalıdır. Çok sayıda görüntü yüklüyorsanız, bu, UI iş parçacığının duraklamasına neden olabilir. (Burada DelayCreation gibi birkaç başka karışıklık var ama sizin sorunuza uymuyorlar.)
Görüntü yüklemek için birkaç yol var, ancak bir BackgroundWorker'da web'den yükleme yapmak için buldum. WebClient veya benzer bir sınıf kullanarak verileri kendiniz indirmeniz gerekecek.
BitmapImage'ın bir WebClient'i dahili olarak kullandığını ve ayrıca çok sayıda hata işleme ve kimlik bilgileri ile farklı durumlar için anlatabilmemiz gereken diğer öğelerin bulunduğunu unutmayın. Bu parçacığı sağlıyorum, ancak yalnızca sınırlı sayıda durumda test edildi. Proxy'lerle, kimlik bilgileriyle veya başka senaryolarla uğraşıyorsanız, bu biraz masaj yapmalısınız.
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);
Bunu basit bir projede denedim ve iyi çalışıyor. Önbelleğe çıkıp çıkmadığı konusunda% 100 değilim, ancak MSDN'den anlatabildiğim, diğer forum soruları ve PresentationCore'a yansıtıcı olarak önbellek vurmalıyım. WebClient, HTTPWebRequest'i saran WebRequest'i ve bu şekilde devam eder ve önbellek ayarları her katmandan geçirilir.
BitmapImage BeginInit/EndInit çifti, gereksinim duyduğunuz ayarları aynı anda ve ardından EndInit sırasında yürütmeyi sağlar. Başka bir özellik belirlemeniz gerekirse, boş kurucuyu kullanmalı ve EndInit'i aramadan önce ihtiyacınız olanı ayarlayarak yukarıdaki gibi BeginInit/EndInit çiftini yazmalısınız.
Genellikle de EndInit sırasında belleğe resim yüklemek için zorlar, bu seçeneği, set
:
image.CacheOption = BitmapCacheOption.OnLoad;
Bu daha iyi çalışma zamanı performansı için mümkün yüksek bellek kullanımını kapalı ticaret yapacak. Bunu yaparsanız, BitmapImage bir URL'den zaman uyumsuzluğu gerektirmedikçe BitmapImage, EndInit içinde eşzamanlı olarak yüklenir.
Daha notlar: UriSource mutlak Uri ve bir http veya https düzeni ise
BitmapImage zaman uyumsuz indirecektir. Endinit'ten sonra BitmapImage.IsDownloading özelliğini kontrol ederek indirip indirmediğini anlayabilirsiniz. DownloadCompleted, DownloadFailed ve DownloadProgress olayları vardır, ancak arka plan iş parçacığı üzerinde ateş etmek için ekstra zor olması gerekir. BitmapImage sadece eşzamansız bir yaklaşım sergilediğinden, indirme işlemi tamamlanana kadar iş parçacığını canlı tutmak için WPF eşdeğeri DoEvents() ile bir while döngüsü eklemeniz gerekir. Bu snippet'indeki çalışır DoEvents için This thread gösterileri kodu: Yukarıdaki yaklaşım çalışsa da
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;
};
bunun nedeni DoEvents() bir kod kokusu vardır, ve bunu WebClient, proxy ya da başka şeyler yapılandırmak izin etmediğini daha iyi performansla yardımcı olabilir. Yukarıdaki ilk örnek bu konuda önerilmektedir.
Eğer BackgroundWorker kodunu gönderebilir miyim? – Rusty