> #region WIN32STDSTUFF > [StructLayoutAttribute(LayoutKind.Sequential)] > public struct RECT > { > public int left; > public int top; > public int right; > public int bottom; > } > #endregion > > #region NM_CustomStructures > [StructLayoutAttribute(LayoutKind.Sequential)] > public struct NMHDR > { > public IntPtr hwndFrom; > public int idFrom; > public int code; > } > > [StructLayoutAttribute(LayoutKind.Sequential)] > public struct NMCUSTOMDRAW > { > public NMHDR hdr; > public int dwDrawStage; > public IntPtr hdc; > public RECT rc; > public uint dwItemSpec; > public uint uItemState; > public IntPtr lItemlParam; > } > > [StructLayoutAttribute(LayoutKind.Sequential)] > public struct NMLVCUSTOMDRAW > { > public NMCUSTOMDRAW nmcd; > public uint clrText; > public uint clrTextBk; > public int iSubItem; > } > > public enum HeaderControlMessages : int > { > HDM_FIRST = 0x1200, > HDM_GETITEMRECT = (HDM_FIRST + 7), > HDM_HITTEST = (HDM_FIRST + 6), > HDM_SETIMAGELIST = (HDM_FIRST + 8), > HDM_GETITEMW = (HDM_FIRST + 11), > HDM_ORDERTOINDEX = (HDM_FIRST + 15) > } > #endregion > > #region Win32Messages > public enum Msg > { > WM_NULL = 0x0000, > WM_ERASEBKGND = 0x0014, > WM_NOTIFY = 0x004E, > WM_COMMAND = 0x0111, > WM_USER = 0x0400 >} > > public enum NotififyMessages > { > NM_FIRST = (0-0), > NM_CUSTOMDRAW = (NM_FIRST-12), > NM_NCHITTEST = (NM_FIRST-14) > } > > public enum ReflectedMessages > { > OCM__BASE = (Msg.WM_USER+0x1c00), > OCM_COMMAND = (OCM__BASE + Msg.WM_COMMAND), > OCM_NOTIFY = (OCM__BASE + Msg.WM_NOTIFY) > } > > public enum OwnerDrawnReturnFlags > { > CDRF_DODEFAULT = 0x00000000, > CDRF_NEWFONT = 0x00000002, > CDRF_SKIPDEFAULT = 0x00000004, > CDRF_NOTIFYPOSTPAINT = 0x00000010, > CDRF_NOTIFYITEMDRAW = 0x00000020, > CDRF_NOTIFYSUBITEMDRAW = 0x00000020, > CDRF_NOTIFYPOSTERASE = 0x00000040 > } > > public enum OwnerDrawnStateFlags : uint > { > CDIS_SELECTED = 0x0001, > CDIS_GRAYED = 0x0002, > CDIS_DISABLED = 0x0004, > CDIS_CHECKED = 0x0008, > CDIS_FOCUS = 0x0010, > CDIS_DEFAULT = 0x0020, > CDIS_HOT = 0x0040, > CDIS_MARKED = 0x0080, > CDIS_INDETERMINATE = 0x0100 > } > > public enum OwnerDrawnDrawStateFlags > { > CDDS_PREPAINT = 0x00000001, > CDDS_POSTPAINT = 0x00000002, > CDDS_PREERASE = 0x00000003, > CDDS_POSTERASE = 0x00000004, > CDDS_ITEM = 0x00010000, > CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT), > CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT), > CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE), > CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE), > CDDS_SUBITEM = 0x00020000 > } > #endregion > > public class OwnerDrawnListView : System.Windows.Forms.ListView > { > [DllImportAttribute("user32.dll", CharSet=CharSet.Auto)] > public static extern int SendMessage(IntPtr hWnd, HeaderControlMessages msg, int wParam, int lParam); > > public OwnerDrawnListView() > { > SetStyle(ControlStyles.UserPaint, true); > FullRowSelect = true; > View = View.Details; > } > > > protected override void WndProc(ref Message newmsg) > { > base.WndProc(ref newmsg); > > switch (newmsg.Msg) > { >// case (int)Msg.WM_ERASEBKGND: >// IntPtr hDC = (IntPtr)newmsg.WParam; >// PaintBackground(hDC); > >// break; > > // WM_NOTIFY message come from the header. > case (int)Msg.WM_NOTIFY: > NMHDR nm1 = (NMHDR)newmsg.GetLParam(typeof(NMHDR)); > > switch(nm1.code) > { > case (int)NotififyMessages.NM_CUSTOMDRAW: >// HeaderOwnerDraw(ref newmsg); > break; > > default: > break; > } > > break; > > // Messages from the list itself are reflected using OCM_NOTIFY. > case (int)ReflectedMessages.OCM_NOTIFY: > NMHDR nm2 = (NMHDR) newmsg.GetLParam(typeof(NMHDR)); > > switch (nm2.code) > { > case (int)NotififyMessages.NM_CUSTOMDRAW: >// ListOwnerDraw(ref newmsg); > break; > > default: > break; > } > > break; > > // Default > default: > break; > } > } > > private bool ListOwnerDraw(ref Message m) > { > m.Result = (IntPtr)OwnerDrawnReturnFlags.CDRF_DODEFAULT; > NMCUSTOMDRAW nmcd = (NMCUSTOMDRAW)m.GetLParam(typeof(NMCUSTOMDRAW)); > IntPtr thisHandle = Handle; > > if ( nmcd.hdr.hwndFrom != Handle) > return false; > > switch (nmcd.dwDrawStage) > { > case (int)OwnerDrawnDrawStateFlags.CDDS_PREPAINT: > // Ask for Item painting notifications > m.Result = (IntPtr)OwnerDrawnReturnFlags.CDRF_NOTIFYITEMDRAW; > break; > > case (int)OwnerDrawnDrawStateFlags.CDDS_ITEMPREPAINT: > m.Result = (IntPtr)OwnerDrawnReturnFlags.CDRF_NOTIFYSUBITEMDRAW; > break; > > case (int)(OwnerDrawnDrawStateFlags.CDDS_ITEMPREPAINT | OwnerDrawnDrawStateFlags.CDDS_SUBITEM): > // Draw our new custom background. > OwnerDrawListItem(ref m); > break; > > default: > break; > } > return false; > } > > void OwnerDrawListItem(ref Message m) > { > NMLVCUSTOMDRAW lvcd = (NMLVCUSTOMDRAW)m.GetLParam(typeof(NMLVCUSTOMDRAW)); > > // Return a structure describing the outcome of the owner drawing process. > >// >// -> Customer drawing goes here <- >// > > Marshal.StructureToPtr(lvcd, m.LParam, true); > m.Result = (IntPtr)OwnerDrawnReturnFlags.CDRF_SKIPDEFAULT; > } >>As you can see the owner drawing technique allows you the ultimate freedom when designing UI features but it does take some effort.
"If ye love wealth better than liberty, the tranquility of servitude better than the animated contest of freedom, go home from us in peace. We ask not your counsel or arms. Crouch down and lick the hands which feed you. May your chains set lightly upon you, and may posterity forget that ye were our countrymen."
~Samuel Adams