Welcome!

.NET Authors: Elizabeth White, Liz McMillan, Eric Carter, Maureen O'Gara, David Weinberger

Related Topics: .NET

.NET: Article

The Thumbnail View Control

Rolling your own controls

Nothing is more frustrating than seeing the functionality you need embedded in one of Microsoft's applications, but not having a reusable component to give you access to the code they already wrote.

This happened in the past with the "cool bars" in Microsoft Office and now with the Thumbnails view in Windows Explorer (View->Thumbnails menu option). We were in the process of writing an application that processes graphical files and decided that having a ThumbnailView would be very useful. So, after looking for the new common control and failing to find one, we decided to write it ourselves. Now, we'll show you how we did it so that you don't have to wait until Microsoft comes out with another batch of common controls.

The first thing we did was hunt for the built-in functionality to get us a thumbnail image. Our hopes went sky high when we saw the Image.GetThumbnailImage method supplied by Microsoft, but those hopes didn't remain too high after we tested the functionality. The method works very simply, but returns sub-par images that are nowhere near the quality of the Thumbnails View in Windows Explorer.

After hunting around for a better thumbnail implementation, we stumbled across an article at vbAccelerator.com that actually used the same API that the Windows Explorer uses to get the thumbnail images. Because it uses the same API, the code also supports non-image files too. Bonus!

Well, now that we figured out the hard stuff, let's put the control together.

The Control

Our plan was to make a Thumbnail View control that is as easy to use as possible. It needs to handle mouse and keyboard navigation and support the concepts of a "current selection" and "launching" an item (through double-click or hitting Enter). It also needs to dynamically change the number of rows and columns based on the size of the container and support a "strip" mode in which all the images are in a single row.

How To Use It
For those of you who just want to use the Thumbnail View, we'll give you the quick out. To use the ThumbnailView, add it to your Windows Form and, in your Form's Load handler, set the "Directory" property to the directory you want browsed. Then, subscribe to the events you want to handle. We expose Events for the client code: SelectionChanged and LaunchFile. The SelectionChanged Event is triggered when - you guessed it - the selection is changed. The Launch-File event is triggered when the user double-clicks an image or hits Enter when an image is selected.

Once an event handler is triggered, the client code can then use the SelectedFileName property to determine which file is Selected or to be launched. Listing 1 contains a snapshot of the code needed to use this control.

How It Works
For those of you who want to see how to write a control like this, we'll go under the hood and see how the image display, mouse and keyboard navigation and event exposure happen.

Basic organization
If you refer to Figure 2, you can see how the ThumbnailView contains a collection of ImageControl objects, each of which contains a PictureBox and a Label.

Mouse and keyboard navigation
Since Mouse clicks are handled by the innermost object first (i.e., The PictureBox gets the clicks first, we need to bubble the events up from the innermost control up to the ThumbnailView where all the logic occurs. In order to do this, we handle the MouseDown, Click and DoubleClick events of the PictureBox in the ImageControl and just proxy them to the ImageControl's handlers (see Listing 2). Now, the ThumbnailView can intercept the mouse events from the ImageControl and will get the events from the PictureBox too.

Keyboard events are automatically propagated up to the outer controls, so we can just override the ProcessCmdKey method in ThumbnailView and intercept the arrow keys and enter key.

Image display
If you've done low-level graphics work before, you might remember that this can be the hardest part. Remember all those BitBlt and MemoryDC device contexts you had to use back in the MFC days? If you responded "no" to that question, consider yourself lucky. Thankfully, Microsoft stepped up to the plate on this one and knocked it out of the park. All we had to do was create an Image object and use the PictureBox control (from System.Windows.Forms). The painting of the image is completely taken care of.

Layout
The Directory property's set method enumerates all the files and puts their fully qualified path into an ArrayList. To lay out the files, we just simply loop through the list and create new image controls based on the file.


	foreach( string file in _files)
	{
		CreateImageControl( file );
	}

In the CreateImageControl function, we create the controls and assign the position of the control based on previously created controls and the current scroll position of the ThumbnailView.

What's Next?

There are a number of additions we would like to make to this Control in the future. Since we didn't have the time to implement them all before the article deadline, we'll list them here so you can get an idea of where we were headed with this. It shouldn't be too difficult to implement them yourself, if needed. Here they are:
  • Abstracting thumbnail generation through an Interface
  • Making more things configurable, like file extensions and thumbnail size
  • Multiple selection support
  • Making the "one-row" version look like the "film strip" in Windows Explorer.
  • Advanced keystroke support (PgUp, PgDn, Home, End, etc)
  • Fix the drag and drop functionality of the ThumbnailView in the Visual Studio.NET designer. (For some reason, the control can't be dropped on a Form.)

Conclusion

As you can see from this article, the .NET Framework provides you with almost everything you need to write your applications. Occasionally, though, you'll need to roll your own controls to get certain functionality. When you do so, you'll find that the building blocks are there for you and can be easily assembled. We hope that you'll find this article a helpful reference when you write your own controls.

More Stories By Thomas McKearney

Thomas McKearney is a developer who works for Applied Information Sciences, a Microsoft and Rational partner based in suburban Washington, D.C.

More Stories By Ben Brouse

Ben Brouse is a developer who works for Applied Information Sciences (http://www.appliedis.com), a Microsoft and Rational Partner based in suburban Washington, D.C.

Comments (14) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Tom McKearney 06/07/06 02:35:10 PM EDT

Some things were simplified to fit the article size and content, so Exceptinos handling and things like that were sacrificed for brevity.

I will post something here if I am allowed to post updated code.

Tom

Tim Overbay 06/07/06 02:21:16 PM EDT

I'm already making one change: The captions underneath each thumbnail are cut off if they're too long. I'm either going to make the captions take up two lines or use the '...' text fit with a tooltip to show the full caption.

Multi-threading, caching, and better error-handling seem to be needed, too.

Tom McKearney 06/07/06 02:05:39 PM EDT

No problem. I hope it works well for you.

I have been using it for a couple of years now, with some extensive changes. I have been meaning to ask my client if I may release changes I have made to the control over time, since they own those code changes.

We will see.

Tim Overbay 06/07/06 02:01:14 PM EDT

This is exactly what I was looking for. Thank you very much for the excellent article and control.

Tom McKearney 06/07/06 01:57:29 PM EDT

Here is a copy of the thumbnailer code I believe that goes with this article:

http://mckearney.com/files/ThumbnailerCode.zip

Let me know if have problems getting that file or it isn't what you expected.

Tom

Tim Overbay 06/07/06 01:48:47 PM EDT

The link to the 'source code' only shows the code to use the control. I cannot find the actual source code for the control itself.

This would be extremely helpful for my current project. Is there some other way I can access the code for this control?

Thank you

Tom McKearney 05/01/06 04:02:38 PM EDT

Manfred: The code is at the bottom of the article. ImageControl is something I wrote for the article.

T

Tom McKearney 05/01/06 03:28:54 PM EDT

Joe: I would take the source code and either include it in your project and then use it like any other control.

otherwise, instantiate one and set its parameters. Then, add it to your form by using this.Controls.Add(...).

Tom

Manfred 03/30/06 03:39:03 AM EST

Well... the article is pretty interesting. But I miss something about how to implement the control in a project. Also, what is the "Imagecontrol"? I can't find it in C#?

Joe Nassour 02/11/06 05:43:56 PM EST

I liked your article. It is exactly what I need to do. However, it does not say how to get to the thumbnailview object so I can put on my form. Do I need to import a specific dll? From where?

thanks

Joe

Duty Editor 10/18/05 09:51:49 AM EDT

Dear Omotoso,

Thank you for your compliment about the article.The source code is indeed at the foot of the page: http://photos.sys-con.com/story/res/44864/source.html

omotoso 10/18/05 09:18:07 AM EDT

please the article is lovely but the code sample is no where to be found

chuck97224 04/27/05 07:34:15 PM EDT

Where's the code Luke? The only thing I see is listing1 that tells you how to use the control

Nothing is more frustrating than seeing the functionality you need in a coding article but no code.

Jordell Jarnell 02/24/05 12:12:18 AM EST

Title of article seemed just what I was looking for but implementation details too scanty for newbie.