Contents
Whilst there seems to be a number of feature-rich filmstrip controls available for web applications, there are precious few for normal windows forms applications. I did read rahulparthe's article but that did not provide the required functionality. So my effort here has been developed from the ground up with no other inspiration.
The control is built into it's own dll, Filmstrip.dll, and uses the Filmstrip
namespace. You can add a reference to the compiled dll or you can directly copy the source files to a folder on your project. The code is currently designed so you can just copy the source files, it doesn't need any extra resources. (This means displayable strings are hard-coded as constants rather than in the string table as they should be.) Once the reference has been added, ensure that it appears in the toolbox, then simply drag the control onto a form.
The Filmstrip control has the following features:
- Dynamically add one or more images.
- Dynamically remove a single image, or clear the entire control.
- Dynamically clear the selection in the control.
- Automatic update of the the thumbnails displayed as the control is resized.
- User-defined location for the thumbnails strip.
- User-defined colour-scheme for the entire control.
- Automatic scrolling - hovering the mouse over a navigation button causes the thumbnails to scroll in the appropriate direction after a configurable delay time.
- Tooltips - Each thumbnail displays it's description and it's index into the collection.
- Editable description - double-clicking on the main image will display a simple form that allows it's description to be amended.
- Full keyboard access - As each thumbnail is a button, users can tab between each thumb and select using the
Space
key. The Home
, End
, PageUp
and PageDown
keys are also supported. The accelerator combination to display the edit description form is also customisable.
- Feedback on control activity via events for when the selection, or the description of the selected image, changes.
- Add custom images to the navigation buttons.
- Design-time support.
- Add a reference to the Filmstrip.dll to your project.
- Drag the
FilmstripControl
onto a form.
- Set the required control properties in the designer.
- Add the images required in the form's OnLoad handler, or elsewhere, as required. (Note that all images have to be associated with a numeric id value.) The sample application displays the 3 different ways of doing this...
filmstripControl.AddImage(
new FilmstripImage(Properties.Resources.Zugspitze as Image,
"Zugspitze, Germany"));
filmstripControl.AddImage(Properties.Resources.ChobeSunset as Image,
"Sunset at Chobe National Park, Zambia");
if (DialogResult.OK == openFileDialog.ShowDialog())
{
List<FilmstripImage> images = new List<FilmstripImage>();
foreach (String file in openFileDialog.FileNames)
{
Image thisImage = Image.FromFile(file);
FilmstripImage newImageObject =
new FilmstripImage(thisImage, file);
images.Add(newImageObject);
}
filmstripControl.AddImageRange(images.ToArray());
}
- Implement any specific functionality required for using the image selected in the Filmstrip control by using the event handlers and appropriate properties.
- Err..... that's it.
The Filmstrip control has a number of public properties. These can be categorised into 2 areas: visual and functional.
The visual properties are used to modify/customise the visual look and feel of the control. It is possibly to change the background colour of the entire control (and also the colour of the selected hightlight), to replace the left and right navigational buttons with custom images and to specify where the thumbnail strip is displayed among other things.
Property |
Read only? |
Description |
ControlBackground |
No |
Specifies the background colour of all items on the filmstrip control. Default value is 'Control'. |
EditDescriptionAccelerator |
No |
Sets the accelerator key combination to display the edit description form for the currently selected image. Default is Ctrl+D. |
ImageNavLeft |
No |
Specifies the image to be used for the left navigation button. If no image is specified the button text will have '<'. |
ImageNavLeftLayout |
No |
Specifies the image layout used for the left navigation button image, if an image is present. Default value is 'Stretch'. |
ImageNavRight |
No |
Specifies the image to be used for the right navigation button. If no image is specified the button text will have '>'. |
ImageNavRightLayout |
No |
Specifies the image layout used for the right navigation button image, if an image is present. Default value is 'Stretch'. |
MainImageLayout |
No |
Specifies the image layout for the image selected into the main viewing area. Default value is 'Center'. |
ScrollHoverDelay |
No |
Specifies the delay interval (in milliseconds) used before scolling the thumbnail view whenever the mouse hovers over a navigation button. Default value is 500ms. |
SelectedHighlight |
No |
Specifies the colour of the highlight surrounding the selected thumbnail image. Default value is 'DarkBlue'. |
ThumbsStripLocation |
No |
Specifies the location of the strip of thumbnail images, either 'Top' or 'Bottom'. Default value is 'Bottom'. |
The functional properties relate to the data used by the control:
Property |
Read only? |
Description |
ImagesCollection |
No |
The images collection. Setting this property will remove any images currently in the collection. |
SelectedImage |
Yes |
The image currently selected in the control. |
SelectedImageDescription |
No |
The description of the image currently selected in the control. |
SelectedImageID |
No |
Specifies the image id of the image currently selected in the control. |
The control has only a few public methods. These were kept to a minimum in order to retain simplicitiy and ease of use:
AddImage |
This method adds a single image to the control. The new image is added at the end of the control's internal collection. (3 overloads.) |
AddImageRange |
This method adds multiple images to the control. The new images are added at the end of the control's internal collection. |
ClearAllImages |
This method removes all images from the control. |
ClearSelection |
This method removes any selection from the control so that no image is selected. |
EnsureThumbIsVisible |
This method ensures that the thumb for the specified image is visible in the thumnbails strip. It does not affect the current selection. |
RemoveImage |
This method removes the specified image from the control. |
Note: At present, AddImage
(all overloads), AddImageRange
and RemoveImage
all cause the entire thumbnails list to be repopulated, which does cause a slight flicker. It is advised that when adding many images after the control has been initially displayed (i.e. not in the OnLoad handler) use the AddImageRange
method, as this will only cause the thumbnails list to be repopulated once.
The control fires 2 different events:
SelectionChanged |
This event is fired when the selected image in the control changes. |
SelectedImageDescriptionChanged |
This event is fired when the description of the selected image changes within the control. |
The Filmstrip.dll assembly contains the following public 'objects':
FilmstripControl |
The actual filmstrip control. |
FilmstripControl.StripLocation |
A simple enum used to specify the position of the thumbnails strip on the control. It currently only has values for 'Top' and 'Bottom'. |
FilmstripImage |
A simple class to encapsulate an image inside the control. |
Each image added to the control is stored internally as a FilmstripImage
object in standard Dictionary
. Each FilmstripImage
has it's own ID - this is required and is a whole number. If an image id is not specified then one is generated during the AddImage
call and returned to the caller. The only invalid value for an image id is -1: this is specified by the static class member NO_SELECTION_ID
.
The most challenging aspect of developing the control has been ensuring that the collection of thumbnails is constructed, populated and rendered correctly, especially when the control is being resized.
The strip of thumbnails is dynamicaly created depending on the the number of images in the control's collection and the current size of the control. The entire strip, including navigation buttons, is contained on a panel so that it can be moved to the desired location on the control. On the strip itself the thumbnails themselves are located on another panel that is sandwiched between the 2 navigation buttons. The navigation buttons are of fixed size and position - i.e. they maintain their position relative to the sides of the control. In this way the panel containing the thumbnails grows or shrinks with the control. The control maintains a collection of all thumbnail Button objects currently in use - the thumbnailControls
member.
Given that each thumbnail panel and button are a fixed size, it is possible to calculate the number of thumbnails that can fit into the parent panel at any time. Whenever the control width alters it checks to see if it is displaying the full number of thumbnails possible, and then adds or removes thumbnails as necessary. In either case we have to account for the fact that window hosting the form may have been maximised or 'un-maximised' so we may have to add or remove more than one thumbnail at a time. This is all done in the AdjustThumbnails
function. So when the control gets bigger:
while ((thumbnailControls.Count < ThumbsForWidth())
&& (thumbnailControls.Count < imagesCollection.Count))
{
int imageIDOfLast = -1;
if (thumbnailControls.Count > 0)
{
imageIDOfLast =
Convert.ToInt32(thumbnailControls[thumbnailControls.Count - 1].Tag.ToString());
}
int newIndex = PushThumbnail();
if ((imageIDOfLast > -1) && (keys[keys.Count - 1] == imageIDOfLast))
{
MoveThumbnailsLeft();
}
else
{
PopulateThumbnail(newIndex);
}
}
But thankfully when the control gets smaller the code is much simpler:
while (thumbnailControls.Count > ThumbsForWidth())
{
PopThumbnail();
}
The sample application provided demonstrates how the Filmstrip control can be easily integrated onto a form. It provides the following functionality:
- How to add images (at load-time and dynamically after loading).
- How to remove images.
- How to clear the control.
- It allows for dynamic changing of many (but not all) of the visual properties.
- It displays details of the image currently selected in the control using only the information provided by the control.
- How to set the control selection.
- How to update the description of the selected image.
There are a few things of note in the sample application:
- The default images are built into the sample application and their initial descriptions are hard-coded.
- There is an internal counter for the image id. This starts at 1 and is incremented with every new image added.
- When adding new images using the 'Add..' button. The full filename is set as the description to each image.
- The application uses a 3rd-party control for the colour picker combos. This control is located in the OfficePickers.dll assembly, details of which can be found in the article: Office 2003 Color Picker.
All code was developed using Visual Studio 2005 Professional and Express editions on Windows XP (Home & Professional). It has not been fully tested using any other versions of Visual Studio, the .Net framework or on other operating systems, as I do not have access to them. (Although limited testing on earlier versions was done on Windows 2000 and Windows 2003 Server.)
- 17/06/2008 - v.1.0 - Initial public release.
- 18/06/2008 - v.1.1
- Corrected namespace usage internally.
- Added Toolbox image.
- Minor change to the naming of the public events (removed the 'On' at the start).
- Added design-time support.
- Made
EnsureThumbIsVisible
method public.
- 27/06/2008 - v.1.2
- Some code re-organisation and refactoring.
- Added keyboard handling for use of
Home
, End
, PageUp
and PageDown
keys.
SelectedImageDescription
property now writeable.
- Modified usage of image ids. These can now be omitted when adding images and an image id is assigned internally. As a result a new
AddImage
overload has been created, along with a new overloaded constructor for the FilmstripImage
class. Additionally all AddImage
methods now return the image id of the image added. If required, image ids can now be negative. The only value invalid value is -1, which is specified by the static member NO_SELECTION_ID
.