Transparent State Images in Tree Views

Normal and state images

Both tree view and list view controls can have two images associated with each item: the 'normal' image and the state image. If an item has both, the state image is displayed to the left of the normal image. For MOBZync I needed exactly that: the normal image shows the icon associated with the file or folder and the state image indicates whether the item is Added, Newer, Older or Unchanged, as can be seen in this screenshot.

Ugly state images

Of course, icons support transparency, so the item images look fine, regardless of the background color of the tree view or list view. But the state images I used (PNG files with transparency) showed up extremely ugly in the tree view. I started experimenting with different types of images (GIF, ICO, transparency masks, alpha channels, you name it) but got exactly nowhere. As usual, the thing to do was to get to the bottom of it, so I created a small test project.

A state image test

I set up a form with a tree view and a list view, plus a single image list containing a blue ball (PNG format), a folder icon (PNG format) and a green ball (ICO format). I used that image list for the normal image lists as well as the state image lists for both controls and populated the controls with three test items. The result is ugly:

Missing transparency in tree view state images

The list view has no trouble displaying the transparent state image, but the tree view (on the left) completely misinterprets the transparency information in the image. (Also, the alignment of the state images is not the same as the normal images, although they come from the same image list. And as it turns out, there is another limitation to state images in tree views: you can ony have a maximum of 15 of them! Looks like state images are somewhat of an afterthought with a less-than-complete implementation. My guess is, Microsoft needed check boxes in tree views and list views, and quickly plugged in state image support. To this day, if you set CheckBoxes to True in a tree view or list view that also has a state image list, those images are used instead of the default checkboxes.) 

I'll save you the hours of fruitless experiments trying to get the transparency to show up properly (including testing just about any combination of ColorDepth, ImageSize and TransparentColor on the image list) and cut to the result: you cannot have transparent state images in a tree view. So there.

Faking transparency

That doesn't mean you can't have transparent-looking state images in a tree view, though. In fact, the folder icon used was a PNG file from the Visual Studio Image Library, but it has no transparency - as can be seen when we change the default window background color:

The folder icon is not really transparent

There's the hint to solving this issue: use the background color of the tree view to generate a specific state image list that no longer contains transparency. Fortunately, that's really simple, thanks to the System.Drawing namespace. Here's a fragment of the MOBZync code:

InitializeComponent();
 
// State images for tree views cannot be transparent, so
// we need to create a new image list that contains the same images,
// (only without transparency) from the image list 'stateImageList'.
ImageList newStateImageList = new ImageList();
 
foreach (Image image in stateImageList.Images)
{
  Bitmap bitmap = new Bitmap(stateImageList.ImageSize.Width,
    stateImageList.ImageSize.Height);
  using (Graphics g = Graphics.FromImage(bitmap))
  {
    g.Clear(this.folderTree1.BackColor);
    g.DrawImage(image, 0, 0);
  }
  newStateImageList.Images.Add(bitmap);
}
 
// Now use the new image list as the state image list
// for the tree views
this.folderTree1.StateImageList = newStateImageList;
this.folderTree2.StateImageList = newStateImageList;

The principle is easy: create a new image list (which, incidentally, will have a ColorDepth of 32 bits, ImageSize 16x16 and its TransparentColor set to Transparent). Then, for each original image, add a new Bitmap to the new image list that is first filled using the background color of the tree view, and then has the original image drawn over it - effectively converting the transparency to the background color of the tree view. Using this method, a really nice alpha channel in the original image will work out great, too. The result looks like it should, even on an abnormally green window background:

Good-looking, but fake transparent state images

Don't mind the folder icon: it does not contain any transparency, which explains the white background. And of course, you'll have to intercept the SystemColorsChanged event to re-create the state image list when the default window background color changes.