protected virtual bool HandleReflectNotify(ref Message m)
{
const int NM_CLICK = -2;
const int NM_DBLCLK = -3;
const int NM_RDBLCLK = -6;
const int NM_CUSTOMDRAW = -12;
const int NM_RELEASEDCAPTURE = -16;
const int LVN_FIRST = -100;
const int LVN_ITEMCHANGED = LVN_FIRST - 1;
const int LVN_ITEMCHANGING = LVN_FIRST - 0;
const int LVN_HOTTRACK = LVN_FIRST - 21;
const int LVN_MARQUEEBEGIN = LVN_FIRST - 56;
const int LVN_GETINFOTIP = LVN_FIRST - 58;
const int LVN_GETDISPINFO = LVN_FIRST - 77;
const int LVN_BEGINSCROLL = LVN_FIRST - 80;
const int LVN_ENDSCROLL = LVN_FIRST - 81;
const int LVN_LINKCLICK = LVN_FIRST - 84;
const int LVN_GROUPINFO = LVN_FIRST - 88; // undocumented
const int LVIF_STATE = 8;
bool isMsgHandled = false;
// TODO: Don't do any logic in this method. Create separate methods for each message
NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR));
//System.Diagnostics.Debug.WriteLine(String.Format("rn: {0}", nmhdr->code));
switch (nmhdr.code) {
case NM_CLICK:
// The standard ListView does some strange stuff here when the list has checkboxes.
// If you shift click on non-primary columns when FullRowSelect is true, the
// checkedness of the selected rows changes.
// We avoid all that by just saying we've handled this message.
//System.Diagnostics.Debug.WriteLine("NM_CLICK");
isMsgHandled = true;
this.OnClick(EventArgs.Empty);
break;
case LVN_BEGINSCROLL:
//System.Diagnostics.Debug.WriteLine("LVN_BEGINSCROLL");
isMsgHandled = this.HandleBeginScroll(ref m);
break;
case LVN_ENDSCROLL:
isMsgHandled = this.HandleEndScroll(ref m);
break;
case LVN_LINKCLICK:
isMsgHandled = this.HandleLinkClick(ref m);
break;
case LVN_MARQUEEBEGIN:
//System.Diagnostics.Debug.WriteLine("LVN_MARQUEEBEGIN");
this.isMarqueSelecting = true;
break;
case LVN_GETINFOTIP:
//System.Diagnostics.Debug.WriteLine("LVN_GETINFOTIP");
// When virtual lists are in SmallIcon view, they generates tooltip message with invalid item indicies.
NativeMethods.NMLVGETINFOTIP nmGetInfoTip = (NativeMethods.NMLVGETINFOTIP)m.GetLParam(typeof(NativeMethods.NMLVGETINFOTIP));
isMsgHandled = nmGetInfoTip.iItem >= this.GetItemCount();
break;
case NM_RELEASEDCAPTURE:
//System.Diagnostics.Debug.WriteLine("NM_RELEASEDCAPTURE");
this.isMarqueSelecting = false;
this.Invalidate();
break;
case NM_CUSTOMDRAW:
//System.Diagnostics.Debug.WriteLine("NM_CUSTOMDRAW");
isMsgHandled = this.HandleCustomDraw(ref m);
break;
case NM_DBLCLK:
// The default behavior of a .NET ListView with checkboxes is to toggle the checkbox on
// double-click. That's just silly, if you ask me :)
if (this.CheckBoxes) {
// How do we make ListView not do that silliness? We could just ignore the message
// but the last part of the base code sets up state information, and without that
// state, the ListView doesn't trigger MouseDoubleClick events. So we fake a
// right button double click event, which sets up the same state, but without
// toggling the checkbox.
nmhdr.code = NM_RDBLCLK;
Marshal.StructureToPtr(nmhdr, m.LParam, false);
}
break;
case LVN_ITEMCHANGED:
//System.Diagnostics.Debug.WriteLine("LVN_ITEMCHANGED");
NativeMethods.NMLISTVIEW nmlistviewPtr2 = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW));
if ((nmlistviewPtr2.uChanged & LVIF_STATE) != 0) {
CheckState currentValue = this.CalculateCheckState(nmlistviewPtr2.uOldState);
CheckState newCheckValue = this.CalculateCheckState(nmlistviewPtr2.uNewState);
if (currentValue != newCheckValue) {
// Remove the state indicies so that we don't trigger the OnItemChecked method
// when we call our base method after exiting this method
nmlistviewPtr2.uOldState = (nmlistviewPtr2.uOldState & 0x0FFF);
nmlistviewPtr2.uNewState = (nmlistviewPtr2.uNewState & 0x0FFF);
Marshal.StructureToPtr(nmlistviewPtr2, m.LParam, false);
}
}
break;
case LVN_ITEMCHANGING:
//System.Diagnostics.Debug.WriteLine("LVN_ITEMCHANGING");
NativeMethods.NMLISTVIEW nmlistviewPtr = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW));
if ((nmlistviewPtr.uChanged & LVIF_STATE) != 0) {
CheckState currentValue = this.CalculateCheckState(nmlistviewPtr.uOldState);
CheckState newCheckValue = this.CalculateCheckState(nmlistviewPtr.uNewState);
if (currentValue != newCheckValue) {
// Prevent the base method from seeing the state change,
// since we handled it elsewhere
nmlistviewPtr.uChanged &= ~LVIF_STATE;
Marshal.StructureToPtr(nmlistviewPtr, m.LParam, false);
}
}
break;
case LVN_HOTTRACK:
break;
case LVN_GETDISPINFO:
break;
case LVN_GROUPINFO:
//System.Diagnostics.Debug.WriteLine("reflect notify: GROUP INFO");
isMsgHandled = this.HandleGroupInfo(ref m);
break;
default:
//System.Diagnostics.Debug.WriteLine(String.Format("reflect notify: {0}", nmhdr.code));
break;
}
return isMsgHandled;
}