46

Original Question (see Update below)

I have a WinForms program that needs a decent scrollable icon control with large icons (128x128 or larger thumbnails, really) that can be clicked to hilight or double clicked to perform some action. Preferably there would be minimal wasted space (short filename captions might be needed below each icon; if the filename is too long I can add an ellipsis).

finished version of listview with proper colors, spacing, etc.
(source: updike.org)

I tried using a ListView with LargeIcon (default .View) and the results are disappointing:

screenshot showing tiny icons in LargeIcon view
(source: updike.org)

Perhaps I am populating the control incorrectly? Code:

        ImageList ilist = new ImageList();
        this.listView.LargeImageList = ilist;
        int i = 0;
        foreach (GradorCacheFile gcf in gc.files)
        {
            Bitmap b = gcf.image128;
            ilist.Images.Add(b);
            ListViewItem lvi = new ListViewItem("text");
            lvi.ImageIndex = i;
            this.listView.Items.Add(lvi);
            i++;
        }

I need large icons with little empty space, not large empty space with embarrassingly small icons.

  1. Is there a .NET control that does what I need?
    • Is there a favorite third party control that does this?
    • If not, which control would be best to inherit and tweak to make it work?
    • Should I break down and make a custom Control (which I have plenty of experience with... just don't want to go to that extreme since that is somewhat involved).

I found this tutorial about OwnerDraw but work from that basically amounts to number 3 or 4 above since that demo just shows how to spice up the rows in the details view.

Update

Adding the line

ilist.ImageSize = new Size(128, 128);

before the for loop fixed the size problem but now the images are palette-ized to 8-bit (looks like system colors?) even though the debugger shows that the images are inserted into the ImageList as 24bpp System.Drawing.Bitmap's:

large icons, finally
(source: updike.org)

  1. How do I (can I?) make the images show in full 24 bit color?
    • The spacing around the icons is still rather wasteful... how do I fix that? Can I?

Update 2

Along with adding the line

ilist.ColorDepth = ColorDepth.Depth24Bit;

next after setting ilist.ImageSize, I followed arbiter's advice and changed the spacing:

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public int MakeLong(short lowPart, short highPart)
{
    return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}

public void ListView_SetSpacing(ListView listview, short cx, short cy)
{
    const int LVM_FIRST = 0x1000;
    const int LVM_SETICONSPACING = LVM_FIRST + 53;
    // http://msdn.microsoft.com/en-us/library/bb761176(VS.85).aspx
    // minimum spacing = 4
    SendMessage(listview.Handle, LVM_SETICONSPACING,
    IntPtr.Zero, (IntPtr)MakeLong(cx, cy));

    // http://msdn.microsoft.com/en-us/library/bb775085(VS.85).aspx
    // DOESN'T WORK!
    // can't find ListView_SetIconSpacing in dll comctl32.dll
    //ListView_SetIconSpacing(listView.Handle, 5, 5);
}

///////////////////////////////////////////////////////////

ListView_SetSpacing(this.listView, 128 + 12, 128 + 4 + 20);

The ListView control may not be perfect or have the defaults I'd expect (like a Spacing property) but I'm glad I could tame it, in the end:

alt text
(source: updike.org)

By the way, to maintain the proper aspect ratio for the thumbnails, I had to make my own 128x128 bitmaps, clear the background to match the control, and center those images:

public void CenterDrawImage(Bitmap target, Color background, Bitmap centerme)
{
    Graphics g = Graphics.FromImage(target);
    g.Clear(background);
    int x = (target.Width - centerme.Width) / 2;
    int y = (target.Height - centerme.Height) / 2;
    g.DrawImage(centerme, x, y);
    g.Dispose();
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Jared Updike
  • 7,165
  • 8
  • 46
  • 72
  • 2
    ComCtl32.dll does not have ListView_SetIconSpacing (as well as all other ListView_x functions), because they not functions but instead simple c++ defines. Actually ListView in vista have a lot of functional that unavailable in .net without massive native interop. – arbiter Jul 09 '09 at 21:37
  • 1
    I just encountered the very same problem, thanks a bunch :D – Nolonar Jul 15 '13 at 21:50

5 Answers5

14

For update:

  1. Set image list color depth in addition to image size (ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView does not have possibility to change icon spacing, however it can be easily done using Win32. You need to send LVM_SETICONSPACING to your ListView (there is a lot of tutorials how to use SendMessage win32 function in .net, so I think this direction must be enough for you).
arbiter
  • 9,447
  • 1
  • 32
  • 43
5

You could use the FlowLayoutPanel and drop pictureboxes in it. Set the picturebox to a size of 128x128 and the sizemode to 'zoom' (This takes care of resizing your image without loss of aspect ratio). You can even programatically add the pictureboxes.

PictureBox pb = New Picturebox;
 pb.image = gcf.image128;
 FlowLayoutPanel1.Controls.Add(pb)

Since you need to have a label under the picturebox, you could create a Usercontrol like Pastor said that all it has is a picturebox and a label under it. Then that would be the control instance you would add to your flowlayoutpanel.

jvanderh
  • 2,925
  • 4
  • 24
  • 28
  • I might try this. The free scrolling (hopefully) and layout is what I want. The problem is it needs to scroll smoothly. – Jared Updike Jul 09 '09 at 00:29
  • You can control the margin around the pictureboxes (or your control) to set the spacing you need between them using the Margin property of each picturebox. – jvanderh Jul 09 '09 at 17:43
  • After going crazy with that, I did some search and found this interesting article: http://www.codeproject.com/Articles/20013/Image-Thumbnail-Viewer-with-NET – Sauleil Mar 19 '15 at 20:24
5

ObjectListView (an open source wrapper around a .NET ListView) makes it easy to custom draw a Tile view. Have a look at the Complex view on the demo, switch to Tile view when custom draw is enabled: owner drawn tile view
(source: sourceforge.net)

If you only wanted a 128x128 image plus some text details, you wouldn't even need to owner draw it. You could give it a large imagelist, and then mark which bits of textual information you wanted to show on the Tile, using IsTileViewColumn.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Grammarian
  • 6,774
  • 1
  • 18
  • 32
2

Disclaimer: I work for Atalasoft

There is an image thumbnail control in our .NET Imaging SDK, DotImage

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • 1
    The built-in .NET ListView is not as cleanly designed as I would have hoped; I'm surprised that it doesn't "just work", with all of these little details to deal with. I can see how Atlassoft has a market for better designed components! You'd think there would be a control for browsing thumbnails where you just drop your images and "boom", it just works... but perhaps the idea of all these "big" (> 100 pixels :-) images was outlandish when Win95/NT were designed... – Jared Updike Jul 09 '09 at 19:37
  • 1
    @Jared, this is because ListView in time evolute with windows, and still based on ideas designed in Win95. – arbiter Jul 09 '09 at 21:40
1

Making a custom control wouldn't be too bad. I would inherit from Panel or a Usercontrol as I believe both automatically add scrollbars for the content.

Dynamically adding containers (like PictureBoxes) and captions for each image, handling the mousedown or mouseclick event for the container and perhaps drawing a red square around it to show that it is selected. The "hardest" part would be resampling the image to 128x128 if they are not already that size and even that can easily be with GDI+.

  • The resampling to 128x128 (or really, 128xH or Wx128) is already done. I just don't love debugging and making everything all snappy and robust, testing and tweaking it since that takes time. – Jared Updike Jul 09 '09 at 00:30
  • And getting the ListView to work also means I get things like arrow keys and focus/selection for free. – Jared Updike Jul 09 '09 at 19:38