Introduction
I needed a ListView with a taller-than-standard header. Seaching the web, I found that a good number of people are looking for this, but the examples out there are either incredibly complex or just don't work. So I set about figuring out exactly how it's done.
Background
I found the following code on CodeProject and used some of it to learn the techniques used in my demo:
BpCsSharpListView.aspx
This has good info about pretty much anything you'd want to know about creating a custom ListView control, but it doesn't have variable-height headers.
Emery-Emerald.aspx
This does custom header heights... but it's in C++/MFC and I want C#. Regardless, the code is instructive in how to manipulate a ListView "old school", which in the end is what my code does.
ObjectListView.aspx
This does EVERYTHING you could EVER imagine in a ListView, but I found it to be overkill. I only wanted a variable-sized header!
I had also read some articles that say you control the header's height via the font, but I found that to be false. This demo uses no fonts at all.
Using the code
The attached code is a simple VS2008 project that has esssentially two files: the ListView implementation (VHHListView.cs) and a form that demo's it. The form is pretty boilerplate.
I named my ListView class "VHHListView" for "Variable Header Height ListView". This class is the barest-bones implementaion that I could create... the only thing it does is provide a ListView with a variable-height header. Going back to my original web search, there's already plenty of info out there about the exotic depths of owner-draw lists, but really nothing specifically about how to control the header height. Therefore, this class is provided as a how-to on that one concise subject. Incidentally, if you already have custom ListView and want to add variable header height to it, merging my code into yours should be pretty straightforward.
The relevant item - the header height - is controlled via the VHHListView's HeaderHeight
attribute. When embedding a VHHListView in a Form, that's all you need to know. The rest is 100% stock ListView (no custom ColumnHeaders, no owner-draw, no Graphics, etc).
VHHListView's basic technique is this:
- Create a control that subclasses ListView
- Create a HeaderControl class that subclasses NativeWindow
- Upon ListView creation, attach the HeaderControl to the low-level ListView's header's HWND.
- In your HeaderControl's WndProc, process the HDM_LAYOUT message, filling in the message's HDLAYOUT struct with the header geometry.
It's really just that simple, but of course it took many hours' worth of researching, experimenting, and chasing false leads (we've all been there!) before I was able to distill it down to the attached demo.
In the attached code, find VHHListView.HeaderControl.HandleLayout()
- that's where the magic happens.
Points of Interest
I find it very interesting how C# and .NET have made 95% of Windows dev much simpler while making that final 5% much harder. Despite the incredible productivity gains provided by .NET, in order to do anything custom you still gotta know your low-level Win32 which remains fundamentally unchanged from when we wrote for Windows 3.0 using plain C !
History
Initial revision: January 7, 2010