Custom Draw ListView with Double Buffering

For one of my pet projects, I needed to add a graphic to certain ListView rows. I considered owner-drawing the control, but that seemed messy. What I really wanted was a way to draw on top of whatever Windows painted. I couldn't find a nifty .NET way to do this, so remembering a technique from the MFC days, I decided to custom draw the ListView. This would let me inject my own drawing code and let Windows handle the rest. Perfect!

I had originally implemented the ListView using a control style to eliminate the annoying flicker every time the list was repainted. Once I started custom drawing the control, I saw odd artifacts in the ListView's client area when I scrolled or moved the mouse. If I turned off double buffering, it worked fine.

I studied the custom draw process looking for my mistake, but I couldn't find any. I even used the .NET Reflector to look at Microsoft's implementation. The message I'm filtering has a handle to the control's back-buffer. So it seemed like I should just be able to draw directly into that. But no matter what I did, it produced the same artifacts.

After about three days of banging my head, I managed to make it work by drawing into my own buffer and then using BitBlt to copy my image to the control's buffer. I also had to set the double buffer style with a window message rather than using the built-in property, although admittedly, I'm not sure why.

I like visual aids, so here's a code snippet from my project. I changed names and removed a bunch of unnecessary lines for easier reading.

#include "stdafx.h"
#include "MyListViewControl.h"
 
using namespace MyListViewControl;
using namespace System::Drawing;
using namespace System::Windows::Forms;
 
MyListViewControl::MyListViewControl() { }
 
bool MyListViewControl::CustomDraw(Message% m)
{
	System::Drawing::Rectangle^ mprc;
	System::String^ cchQueueIndex;
	ListViewItem^ mpItem;
	LPNMCUSTOMDRAW lpnmcd;
	Graphics^ mpgfx;
	HDC hmemdc;
	RECT sOrderRect;
	RECT sStopRect;
	Brush^ mpbgbr;
	Brush^ mpfgbr;
	int nOrderLen;
	int nOrderOffset;
	int nRightEdge;
	int nRectWidth;
	int nItem;
 
	// Grab the custom draw info
	lpnmcd = (LPNMCUSTOMDRAW)m.LParam.ToPointer();
 
	// Figure out which drawing stage we're in
	switch (lpnmcd->dwDrawStage) {	
 
	// Control Pre-paint
	case (CDDS_PREPAINT):
 
		// Request to be notified during item draw
		__super::WndProc(m);
		m.Result = (System::IntPtr)CDRF_NOTIFYITEMDRAW;
		return true;
 
 
	// List Item Pre-paint
	case (CDDS_ITEMPREPAINT):
 
		// Request to be notified after item draw
		__super::WndProc(m);
		m.Result = (System::IntPtr)CDRF_NOTIFYPOSTPAINT;
		return true;
 
 
	// List Item Post-paint
	case (CDDS_ITEMPOSTPAINT):
 
		__super::WndProc(m);
 
		// Get the current item
		nItem = static_cast<int>(lpnmcd->dwItemSpec);
		mpItem = (ListViewItem^)this->Items[nItem];		
 
		// Get the device context and item bounds
		mpgfx = this->CreateGraphics();
		mprc = this->GetItemRect(nItem, ItemBoundsPortion::Label);
 
		// *** Your custom drawing code here ***
 
		// Copy the bubble to the screen DC
		hmemdc = reinterpret_cast<HDC>(static_cast<void*>(mpgfx->GetHdc()));
		BitBlt( 
			lpnmcd->hdc, 
			sOrderRect.left, 
			mprc->Y, 
			nRectWidth, 
			mprc->Height, 
			hmemdc, 
			sOrderRect.left, 
			mprc->Y, 
			SRCCOPY);
		mpgfx->ReleaseHdc((System::IntPtr)hmemdc);
 
		// Let Windows redraw the border
		m.Result = (System::IntPtr)CDRF_DODEFAULT;
		return true;
	}
 
	return false;
}
 
void MyListViewControl::WndProc(Message% m)
{
	LPNMHDR lpnmhdr;
 
	switch (m.Msg)
	{
 
	// Reflected Notifications
	case (OCM_NOTIFY):
 
		// Get the notification
		lpnmhdr = (LPNMHDR)m.LParam.ToPointer();
		if (lpnmhdr == NULL) break;
 
		// We want custom draw messages
		if (lpnmhdr->code == NM_CUSTOMDRAW  
				&& lpnmhdr->hwndFrom == this->Handle.ToPointer()) {
			if(this->CustomDraw(m))
				return;
		}
 
		break;
 
	}
 
	__super::WndProc(m);
}

And here's the header file with the double buffering message call:

#pragma once
 
namespace MyListView
{
	public ref class MyListView : 
		public System::Windows::Forms::ListView
	{
 
	private:
		bool CustomDraw(System::Windows::Forms::Message% m);
 
	public:
		virtual property bool DoubleBuffered
		{
			bool get() override
			{
				LRESULT lStyles = ::SendMessage( 
					(HWND) this->Handle.ToPointer(), 
					LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
				return (lStyles & LVS_EX_DOUBLEBUFFER) != 0;
			}
 
			void set (bool fValue) override
			{
				// I tried using the DoubleBuffered property, but I
				// get artifacts. So, let's do this the MFC way...
				::SendMessage( 
					(HWND) this->Handle.ToPointer(), 
					LVM_SETEXTENDEDLISTVIEWSTYLE, 
					LVS_EX_DOUBLEBUFFER, 
					LVS_EX_DOUBLEBUFFER);
			}
		}
 
	protected:
		virtual void WndProc(System::Windows::Forms::Message% m) override;
 
	public:
		MyListViewControl();
 
	};
}

I spent days searching online and couldn't find anyone who talked about custom drawing a .NET ListView with double buffering. I hope somebody will find this useful.