Click here to Skip to main content
15,891,864 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
I am trying to load thumbnail images (mp3 album cover art) from a web server into a vb.net Windows.Forms.Listbox. I do this in the .drawitem event. This works as long as there is a fast and stable connection. But of course the UI freezes when the download is interrupted somehow. So I need to do this async somehow.

How would you guys go about this? Many many other programs out there do this.

I was thinking of loading a default image first and then updating the listbox as images come in. Would this be effective? And how best to implement this?

What I have tried:

I tried triggering an async download for every .drawitem event. But this resulted in many downloads at the same time, freezing the UI even more. Especially when scrolling.
Posted
Updated 11-May-16 21:49pm
v2
Comments
Sergey Alexandrovich Kryukov 9-May-16 10:36am    
It depends. First of all, what is "ListBox"? Which one? Full type name, please.
—SA
fanoftheplanet 11-May-16 8:19am    
Thanks Sergey,

I rephrased my question.
Sergey Alexandrovich Kryukov 11-May-16 10:36am    
I see, thank you. It should be "ListBox", not "Listbox".

Now, the problem of parallel downloading of images is itself easy. The real problem is: what are you going to show in UI while images are downloaded? As I understand, they should be shown in UI. So, would you explain how you see the design. You probably will need to show something else.

(I must note, the whole idea of downloading something on each application start, or something like that, sounds quite questionable.)

—SA
fanoftheplanet 11-May-16 14:26pm    
Have you ever used spotify? If you lookup a song it shows a list of possible matches along with the cover art. That's exactly what I want to accomplish. People look up songs in an online MySQL database and get a list of possible matches with their respective coverart.

Now, the problem is that I want to use a ListBox for this, and that while downloading the coverart, the listbox can't complete it's drawing, and thus freezes the UI.

So I am looing for a way to fill a ListBox async.
Sergey Alexandrovich Kryukov 11-May-16 19:40pm    
No, I did not use it. Could you simply answer my question?
—SA

Also look at the Proxy Pattern described by Gamma et al (the "Gang of Four"). Such slow loading of images was taken as an example for the motivation behind that pattern.
 
Share this answer
 
You can have a permanently working thread which is driven by the blocking queue/collection. You feed, for example, URLs to it, and it gives you downloading images on output, in a regular, non-blocking queue. This way, if you don't have a task for this thread, it will spend zero CPU time, waiting in a wait state.

I described all this in my article Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

You don't need to use my queue class, because you can use the template class System.Collections.Concurrent.BlockingCollection<>, if your target .NET version is 4.0 or later: BlockingCollection(T) Class (System.Collections.Concurrent)[^].

The value of my article is that explain the principles of operation and important use cases in detail.

Now, Windows.Forms.ListBox is not designed to show any images. If you completely override its graphic rendering, but it would defeat the purpose of using this class completely. Therefore, you need to use something else. One suitable control which can show image would be System.Windows.Forms.ListView:
ListView Class (System.Windows.Forms)[^].

Now you can use the UI without freezing. At first, you can show some predefined "image-is-not-yet-ready" image in the list view. As images are downloaded, you can replace the predefined images with the downloaded ones as they are ready. How? You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke(),
Problem with Treeview Scanner And MD5.

See also more references on threading:
.NET event on main thread,
How to get a keydown event to operate on a different thread in vb.net,
Control events not firing after enable disable + multithreading.

—SA
 
Share this answer
 
Comments
fanoftheplanet 12-May-16 4:37am    
Thanks Sergey for this extensive answer!
I will spend this weekend to give it a try. Because of various reasons I will stick with my ListBox though. Currently I am overriding the .drawitem event and simply paiting the image using Graphics.DrawImage. This works for me. But the principle is the same if I am correct.
Sergey Alexandrovich Kryukov 12-May-16 8:41am    
You are right, the principle is the same.
Well you accept the solution formally?
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900