I had similar problem. I have solved it by implementing my own queue for downloading images. Just download one image at the time, so you will have just one thread for it.
You may think that images will be downloaded slower, but it's not true. Downloading 5 images one by one takes the same amount of time when downloading all 5 at the same time. I tested it in my own app.
Here's my example. First, I have created a class to store basic info about videos: url to a thumbnail and the thumbnail itself as ImageSource, so you can easily bind it to Source property of Image in XAML.
public class VideoItem
{
public string Url { get; private set; }
public ImageSource Thumbnail { get; set; }
public VideoItem(string url)
{
this.Url = url;
}
}
The next class will store all the videos in one observable list, so you can use it in binding. The list will grow as thumbnails will be downloaded, one by one.
public class VideoLibrary
{
private WebClient thumbnailDownloader = new WebClient();
private Queue<VideoItem> downloadQueue = new Queue<VideoItem>();
private bool isBusy = false;
public ObservableCollection<VideoItem> Videos = new ObservableCollection<VideoItem>();
public VideoLibrary()
{
thumbnailDownloader.OpenReadCompleted += OnThumbnailDownloaded;
}
// It will not start downloading process but only add a new video item (without thumbnail) to download queue.
public void Download(string url)
{
downloadQueue.Enqueue(new VideoItem(url)); // Just add to queue.
CheckQueue();
}
// Check whether there are new thumbnails to download. If so, start downloading just one.
private void CheckQueue()
{
if (isBusy) // Stop! Downloading in progress...
return;
if (downloadQueue.Count > 0)
{
isBusy = true;
VideoItem item = downloadQueue.Peek();
thumbnailDownloader.OpenReadAsync(new Uri(item.Url));
}
}
// One thumbnail has been downloaded. We can add it to the list of videos and check the queue again.
private void OnThumbnailDownloaded(object sender, OpenReadCompletedEventArgs e)
{
isBusy = false;
if (e.Cancelled)
{
CheckQueue(); // Just try again.
}
else if (e.Error != null)
{
downloadQueue.Dequeue(); // Skip this video (thumbnail), check the next one.
CheckQueue();
}
else if (downloadQueue.Count > 0)
{
VideoItem item = downloadQueue.Dequeue(); // Remove the video from queue.
WriteableBitmap bitmap = new WriteableBitmap(null);
bitmap.SetSource(e.Result);
item.Thumbnail = bitmap; // Thumbnail is ready to use.
Videos.Add(item); // Add to list.
CheckQueue();
}
}
}