Menu

Drawing Themed Progress Bars manually

October 6, 2013 - C#, Programming

Within my Updating component, Each Element is given a little Progress Bar right within the ListView. It’s drawn using a Gradient background. I’ve given passing thought to the idea of figuring out how to draw the standard Themed Progress bar within the ListView. Today I decided to delve into the seedy underbelly that is the Theme API and sort out how to do exactly that.

The Theme API

The Theme API resides in uxtheme.dll. Using a ‘theme’ component involves three steps:

  1. using the OpenThemeData() function to get a handle to the Theme.
  2. using the DrawThemeBackground() and DrawThemeText() functions to draw applicable parts of that theme element.
  3. closing the theme

At it’s core, Themes are really just groups of images; OpenThemeData() grabs a block of images, and you use the parameters of DrawThemeBackground() and DrawThemeText() to select which portion of the image to use. The Theme API refers to these as “parts” and “States”. The first step to using the Theme API is, of course, to declare the Functions you will be using. Unfortunately while the Functions themselves are well-documented, what is less available is the actual Constants for using the functions; so while I was able to grab some useful declarations from PInvoke.NET I had to use the Windows SDK to recreate the enumerations. Since I am only interested in the Progress Bar portions at this time, I only recreated the appropriate enumerations for them. Here is the class I came up with.

It’s worth noting there is actually a lot in common between some of the Theme Elements, so it might actually make sense for a “full API” sort of implementation that handles all the different cases in a early-bound fashion that let’s you choose the appropriate component. They all use the same functions so it would be a matter of separating each specific type into a different implementation of an abstract class of some sort. But that is for another post for sure. Here we are focused on the progressbar. This code draws the ProgressBar on the given Graphics Object by grabbing it’s DC and using the Theme API functions. Also note the “Default” action which attempts to draw a progressbar the theme API, by simply drawing a plain-style progressbar box. This is to make sure it still works if Themes are disabled on the system it runs on.

So now the question is how do we utilize this for something like a ListView Subitem? The answer is surprisingly… (or perhaps relatively) easily- we simply set the ownerDraw property and override the appropriate functions. I created this sample project which simply advances and shrinks the progressbar values over time by different degrees in a number of List Items. To do this I created a relatively simple Wrapper class around some simple data. This is my preferred pattern when working with the ListView- I typically attach a Data Class to each ListItem through the Tag Property, which allows me to add all sorts of useful data- this can be particularly useful in cases where Delegates or actions are passed ListViewItem’s.

With that out of the way, I could work on the bulk of things. The Sample Program is to eliminate the surrounding faff if I was to simply release the Updater as is, which doesn’t really work well as a simple demonstration of the ProgressBar functionality. Here is the Code behind for the Form itself:

It is reasonably short. In short the Form Creates a thread that iterates over all items and advances their progress (or decrements it) each time, and then forces it to refresh. The Actual drawing logic is in lvwDisplay_DrawSubItem, which basically just draws the item with the given progress within the set bounds for Index 1.

lvwpbar

Behold! The result! Beautiful, really. The ThemePaint Class can also paint the Error and Paused Progressbars. One thing I’ve tried was getting the “marquee” effect properly- there appears to be a way to do so but I’ve yet to work out the best way to get the appropriate effect. Perhaps in a future post I will generic-ize the ThemePaint class to a set of classes for the various Them-able things that can be drawn, though I think such a class may have reasonably dubious value, it might be a good exercise.

Have something to say about this post? Comment!