Do you mind scrolling vertically?
I would start with the DataGridView control as a base and create the following implementation:
1) Create custom column and celltype deriving from DataGridViewImageColumn. You could call them "CronosNetImageColumn", "CronosNetImageCell".
2) Create a class "CronosImageDetails" to hold the cell data (include properties for display text and image url). This will be passed in as the value for each cell. Ex:
ImageGrid.Rows.Add(new CronosImageDetails { DisplayText="Day at the Beach", ImageURL="http://...beach.jpg" });
3) Override the cell Paint() to use a WebClient to get the image and use e.Graphics.DrawImage(ImageObtainedFromWebClient) to paint the image to the cell. You could use e.Graphics.DrawString((CronosImageDetails)value.DisplayText,...) to overlay the text in the cell.
This quick solution would get you a scrolling imagelist that only loads images as the user scrolls through the list and provides a solid base for improvement.
Recommended further optimizations:
A) Create a backbuffer bitmap and graphics for drawing cell data.
B) Setup Paint() to simply paint the backbuffer instead of doing the work to get the image
C) Create a new cell method LoadImage() that spawns a new thread that downloads the image and paints it onto the back buffer.
D) Have Paint() (or a seperate helper thread) track the direction and acceleration of scrolling and estimate which cells need to be preloaded. Trigger LoadImage() on those cells.
E) Initialize the back buffer of each cell with a loading image.
F) Track and use empirical data from the image loading times to help determine which cells need to be preloaded.