Click here to Skip to main content
Click here to Skip to main content
Go to top

Image Thumbnail Preview in DataGridView

, 16 Sep 2008
Rate this:
Please Sign up or sign in to vote.
Shows an implementation of displaying images in a DataGridView with image resizing and paging.

Introduction

This is an implementation showing how to display thumbnail images in a DataGridView, with image resizing and paging. The main reason I created this was to allow users to preview thousands of images quickly and efficiently, whilst still having the core functions of the DataGridView, e.g., selecting cells etc.

Other solutions I have seen use owner panels or other controls, which work well, but don't allow a user to select images. Also, since the controls are owner drawn, they don't have the built-in events like SelectIndexChanged etc., which, in my scenario, makes them unusable. Other solutions I have seen only display a main image with previous and next previews, like a film strip preview. Again, I couldn't use them since I had a requirement to display thousands of images and the ability to navigate quickly through them.

So, if it saves someone some time, or gives them inspiration, then good.

ImageDataGridView.png

Demo/Sample

The implementation will attempt to dynamically create the correct number of columns to fit the DataGridView width. The images are reloaded when the DataGridView resizes to fit the correct width.

A slider control is used to select the image thumbnail size. When the value changes, the images are reloaded, with the current set of images at the new selected image size.

The number of images displayed per page can be modified through the drop down list. If the value changes, then the images are redisplayed from the beginning; this is purely to make the implementation easier!

Code

The column widths are calculated using the following code, which allows us to dynamically create the required number of columns to fit the actual width of the DataGridView:

int numColumnsForWidth = (dataViewImages.Width - 10) / (_imageSize + 20);

Another requirement was to display the minimum number of rows required for the number of images per page, the reason being I wanted it to look as professional as possible. To calculate the number of rows, we need to calculate the number of images that are to be displayed, then use the number of columns required to fit the DataViewGrid. Next, we use the modulus operator to check for a remainder to the calculation; if we get a result, then we add another row to display the overfill:

numRows = numImagesRequired / numColumnsForWidth; 

// Do we have a an overfill for a row
if (numImagesRequired % numColumnsForWidth > 0) 
{ 
   numRows += 1; 
}

The code dynamically creates the columns and rows using the previously calculated values. The value of 20 is simply a value used to create a border around the image, so that the user can see what images are selected:

// Dynamically create the columns
{
    dataViewImages.Columns.Add(dataGridViewColumn);
    dataViewImages.Columns[index].Width = _imageSize + 20;
}

// Create the rows
for (int index = 0; index < numColumnsForWidth; index++)
{
    DataGridViewImageColumn dataGridViewColumn = 
                            new DataGridViewImageColumn();

    dataViewImages.Rows.Add();
    dataViewImages.Rows[index].Height = _imageSize + 20;
}

The images are dynamically loaded from a previously loaded List<string> variable, which contains the image paths. The actual images are loaded from the file system. The code assigns the file name to the tooltip so that the image can be easily identified:

// Load the image from the file and add to the DataGridView
Image image = Helper.ResizeImage(_files[index], 
                                 _imageSize, 
                                 _imageSize, 
                                 false);

dataViewImages.Rows[rowIndex].Cells[columnIndex].Value = image;
dataViewImages.Rows[rowIndex].Cells[columnIndex].ToolTipText = 
                    Path.GetFileName(_files[index]);

The above code references a Helper.ResizeImage function, which is a simple routine that will, strangely enough, resize an image in memory:

public static Image ResizeImage(string file,
                                     int width,
                                     int height,
                                     bool onlyResizeIfWider)
{
    using (Image image = Image.FromFile(file))
    {
        // Prevent using images internal thumbnail
        image.RotateFlip(RotateFlipType.Rotate180FlipNone);
        image.RotateFlip(RotateFlipType.Rotate180FlipNone);

        if (onlyResizeIfWider == true)
        {
            if (image.Width <= width)
            {
                width = image.Width;
            }
        }

        int newHeight = image.Height * width / image.Width;
        if (newHeight > height)
        {
            // Resize with height instead
            width = image.Width * height / image.Height;
            newHeight = height;
        }

        Image NewImage = image.GetThumbnailImage(width, 
                                                 newHeight, 
                                                 null, 
                                                 IntPtr.Zero);

        return NewImage;
    }
}

Because some rows will have cells without images, due to the number of images being displayed not being equal to the number of rows * the number of columns, we need to set the cell to a null value, since a generic image not found icon will be displayed otherwise, which is unsightly:

// Blank the unused cells
if (numGeneratedCells > numImagesRequired)
{
    for (int index = 0; index < 
         numGeneratedCells - numImagesRequired; index++)
    {
        DataGridViewCellStyle dataGridViewCellStyle = 
                              new DataGridViewCellStyle();
        dataGridViewCellStyle.NullValue = null;
        dataGridViewCellStyle.Tag = "BLANK";
        dataViewImages.Rows[rowIndex].Cells[columnIndex + 
                            index].Style = dataGridViewCellStyle;
    }
}

The rest of the code deals with checking list boundary conditions to deal with situations like the user displaying less images than the number of images per page setting. Also, another key check is to ensure that we can display all the images when we get to the end of the list.

History

  • v1.0.0 - Initial release.

License

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

Share

About the Author

Mark Woan

United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
GeneralMy vote of 3 Pinmembersharry2kool27-Jun-12 20:34 
Generalfirst comment Pinmembershenqiboy30-May-12 16:25 
Generalnice Pinmembermarcusquigley5-Feb-09 6:14 
GeneralRe: nice Pinmembermarcusquigley5-Feb-09 6:41 
GeneralNot able to open in Lower version PinmemberCode4Help31-Dec-08 2:48 
JokeThanks! Pinmembersuperdelo10-Dec-08 0:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 16 Sep 2008
Article Copyright 2008 by Mark Woan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid