protected override void OnMouseUp(MouseEventArgs e) { // Detect which column was clicked and handle accordingly const int LVM_FIRST = 0x1000; const int LVM_SUBITEMHITTEST = LVM_FIRST + 57; NativeMethods.LVHITTESTINFO hitInfo = new NativeMethods.LVHITTESTINFO(); hitInfo.pt = new Point(e.X, e.Y); IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.LVHITTESTINFO))); Marshal.StructureToPtr(hitInfo, pointer, true); Message message = Message.Create(Handle, LVM_SUBITEMHITTEST, IntPtr.Zero, pointer); DefWndProc(ref message); hitInfo = (NativeMethods.LVHITTESTINFO)Marshal.PtrToStructure( pointer, typeof(NativeMethods.LVHITTESTINFO)); Marshal.FreeHGlobal(pointer); if(hitInfo.iItem >=0 && hitInfo.iSubItem == 1) { // Flip the load on startup flag PluginListItem item = (PluginListItem)Items[hitInfo.iItem]; item.PluginInfo.IsLoadedAtStartup = !item.PluginInfo.IsLoadedAtStartup; Invalidate(); return; } base.OnMouseUp(e); }
/// <summary> /// Perform a hit test using the Windows control's SUBITEMHITTEST message. /// This provides information about group hits that the standard ListView.HitTest() does not. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> protected OlvListViewHitTestInfo LowLevelHitTest(int x, int y) { // If it's not even in the control, don't bother with anything else if (!this.ClientRectangle.Contains(x, y)) return new OlvListViewHitTestInfo(null, null, 0, null); //if (Control.ModifierKeys == Keys.Control) // System.Diagnostics.Debugger.Break(); // Call the native hit test method, which is a little confusing. NativeMethods.LVHITTESTINFO lParam = new NativeMethods.LVHITTESTINFO(); lParam.pt_x = x; lParam.pt_y = y; int index = NativeMethods.HitTest(this, ref lParam); // Setup the various values we need to make our hit test structure bool isGroupHit = (lParam.flags & (int)HitTestLocationEx.LVHT_EX_GROUP) != 0; OLVListItem hitItem = isGroupHit || index == -1 ? null : this.GetItem(index); OLVListSubItem subItem = (this.View == View.Details && hitItem != null) ? hitItem.GetSubItem(lParam.iSubItem) : null; // Figure out which group is involved in the hit test. This is a little complicated: // If the list is virtual: // - the returned value is list view item index // - iGroup is the *index* of the hit group. // If the list is not virtual: // - iGroup is always -1. // - if the point is over a group, the returned value is the *id* of the hit group. // - if the point is not over a group, the returned value is list view item index. OLVGroup group = null; if (this.ShowGroups && this.OLVGroups != null) { if (this.VirtualMode) { group = lParam.iGroup >= 0 && lParam.iGroup < this.OLVGroups.Count ? this.OLVGroups[lParam.iGroup] : null; } else { if (isGroupHit) { foreach (OLVGroup olvGroup in this.OLVGroups) { if (olvGroup.GroupId == index) { group = olvGroup; break; } } } } } OlvListViewHitTestInfo olvListViewHitTest = new OlvListViewHitTestInfo(hitItem, subItem, lParam.flags, group); // System.Diagnostics.Debug.WriteLine(String.Format("HitTest({0}, {1})=>{2}", x, y, olvListViewHitTest)); return olvListViewHitTest; }
private unsafe void WmReflectNotify(ref Message m) { NativeMethods.NMHDR* nmhdr = (NativeMethods.NMHDR*)m.LParam; switch (nmhdr->code) { case NativeMethods.NM_CUSTOMDRAW: CustomDraw(ref m); break; case NativeMethods.LVN_BEGINLABELEDITA: case NativeMethods.LVN_BEGINLABELEDITW: { NativeMethods.NMLVDISPINFO_NOTEXT nmlvdp = (NativeMethods.NMLVDISPINFO_NOTEXT)m.GetLParam(typeof(NativeMethods.NMLVDISPINFO_NOTEXT)); LabelEditEventArgs e = new LabelEditEventArgs(nmlvdp.item.iItem); OnBeforeLabelEdit(e); m.Result = (IntPtr)(e.CancelEdit ? 1 : 0); listViewState[LISTVIEWSTATE_inLabelEdit] = !e.CancelEdit; break; } case NativeMethods.LVN_COLUMNCLICK: { NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW)); listViewState[LISTVIEWSTATE_columnClicked] = true; columnIndex = nmlv.iSubItem; break; } case NativeMethods.LVN_ENDLABELEDITA: case NativeMethods.LVN_ENDLABELEDITW: { listViewState[LISTVIEWSTATE_inLabelEdit] = false; NativeMethods.NMLVDISPINFO nmlvdp = (NativeMethods.NMLVDISPINFO)m.GetLParam(typeof(NativeMethods.NMLVDISPINFO)); LabelEditEventArgs e = new LabelEditEventArgs(nmlvdp.item.iItem, nmlvdp.item.pszText); OnAfterLabelEdit(e); m.Result = (IntPtr)(e.CancelEdit ? 0 : 1); // from msdn: // "If the user cancels editing, the pszText member of the LVITEM structure is NULL" if (!e.CancelEdit && nmlvdp.item.pszText != null) Items[nmlvdp.item.iItem].Text = nmlvdp.item.pszText; break; } case NativeMethods.LVN_ITEMACTIVATE: OnItemActivate(EventArgs.Empty); break; case NativeMethods.LVN_BEGINDRAG: { // the items collection was modified while dragging // that means that we can't reliably give the user the item on which the dragging started // so don't tell the user about this operation... // vsWhidbey 235027 if (!this.ItemCollectionChangedInMouseDown) { NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW)); LvnBeginDrag(MouseButtons.Left, nmlv); } break; } case NativeMethods.LVN_BEGINRDRAG: { // the items collection was modified while dragging // that means that we can't reliably give the user the item on which the dragging started // so don't tell the user about this operation... // vsWhidbey 235027 if (!this.ItemCollectionChangedInMouseDown) { NativeMethods.NMLISTVIEW nmlv = (NativeMethods.NMLISTVIEW)m.GetLParam(typeof(NativeMethods.NMLISTVIEW)); LvnBeginDrag(MouseButtons.Right, nmlv); } break; } case NativeMethods.LVN_ITEMCHANGING: { NativeMethods.NMLISTVIEW* nmlv = (NativeMethods.NMLISTVIEW*)m.LParam; if ((nmlv->uChanged & NativeMethods.LVIF_STATE) != 0) { // Because the state image mask is 1-based, a value of 1 means unchecked, // anything else means checked. We convert this to the more standard 0 or 1 CheckState oldState = (CheckState)(((nmlv->uOldState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1); CheckState newState = (CheckState)(((nmlv->uNewState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1); if (oldState != newState) { ItemCheckEventArgs e = new ItemCheckEventArgs(nmlv->iItem, newState, oldState); OnItemCheck(e); m.Result = (IntPtr)(((int)e.NewValue == 0 ? 0 : 1) == (int)oldState ? 1 : 0); } } break; } case NativeMethods.LVN_ITEMCHANGED: { NativeMethods.NMLISTVIEW* nmlv = (NativeMethods.NMLISTVIEW*)m.LParam; // Check for state changes to the selected state... if ((nmlv->uChanged & NativeMethods.LVIF_STATE) != 0) { // Because the state image mask is 1-based, a value of 1 means unchecked, // anything else means checked. We convert this to the more standard 0 or 1 CheckState oldValue = (CheckState)(((nmlv->uOldState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1); CheckState newValue = (CheckState)(((nmlv->uNewState & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) == 1 ? 0 : 1); if (newValue != oldValue) { ItemCheckedEventArgs e = new ItemCheckedEventArgs(Items[nmlv->iItem]); OnItemChecked(e); } int oldState = nmlv->uOldState & NativeMethods.LVIS_SELECTED; int newState = nmlv->uNewState & NativeMethods.LVIS_SELECTED; // Windows common control always fires // this event twice, once with newState, oldState, and again with // oldState, newState. // Changing this affects the behaviour as the control never // fires the event on a Deselct of an Items from multiple selections. // So leave it as it is... if (newState != oldState) { if (this.VirtualMode && nmlv->iItem == -1) { if (this.VirtualListSize > 0) { ListViewVirtualItemsSelectionRangeChangedEventArgs lvvisrce = new ListViewVirtualItemsSelectionRangeChangedEventArgs(0, this.VirtualListSize-1, newState != 0); OnVirtualItemsSelectionRangeChanged(lvvisrce); } } else { // APPCOMPAT // V1.* users implement virtualization by communicating directly to the native ListView and // by passing our virtualization implementation. // In that case, the native list view may have an item under the mouse even if our wrapper thinks the item count is 0. // And that may cause GetItemAt to throw an out of bounds exception. // See VSW 418791. if (this.Items.Count > 0) { ListViewItemSelectionChangedEventArgs lvisce = new ListViewItemSelectionChangedEventArgs(this.Items[nmlv->iItem], nmlv->iItem, newState != 0); OnItemSelectionChanged(lvisce); } } // VSWhidbey 549967 - Delay SelectedIndexChanged event because the last item isn't present yet. if (this.Items.Count == 0 || this.Items[this.Items.Count - 1] != null) { this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped] = false; OnSelectedIndexChanged(EventArgs.Empty); } else { this.listViewState1[LISTVIEWSTATE1_selectedIndexChangedSkipped] = true; } } } break; } case NativeMethods.NM_CLICK: WmNmClick(ref m); // FALL THROUGH // goto case NativeMethods.NM_RCLICK; case NativeMethods.NM_RCLICK: NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); int displayIndex = GetIndexOfClickedItem(lvhi); MouseButtons button = nmhdr->code == NativeMethods.NM_CLICK ? MouseButtons.Left : MouseButtons.Right; Point pos = Cursor.Position; pos = PointToClientInternal(pos); if (!ValidationCancelled && displayIndex != -1) { OnClick(EventArgs.Empty); OnMouseClick(new MouseEventArgs(button, 1, pos.X, pos.Y, 0)); } if (!listViewState[LISTVIEWSTATE_mouseUpFired]) { OnMouseUp(new MouseEventArgs(button, 1, pos.X, pos.Y, 0)); listViewState[LISTVIEWSTATE_mouseUpFired] = true; } break; case NativeMethods.NM_DBLCLK: WmNmDblClick(ref m); // FALL THROUGH // goto case NativeMethods.NM_RDBLCLK; case NativeMethods.NM_RDBLCLK: NativeMethods.LVHITTESTINFO lvhip = new NativeMethods.LVHITTESTINFO(); int index = GetIndexOfClickedItem(lvhip); if (index != -1) { //just maintain state and fire double click.. in final mouseUp... listViewState[LISTVIEWSTATE_doubleclickFired] = true; } //fire Up in the Wndproc !! listViewState[LISTVIEWSTATE_mouseUpFired] = false; //problem getting the UP... outside the control... // CaptureInternal = true; break; case NativeMethods.LVN_KEYDOWN: if (CheckBoxes) { NativeMethods.NMLVKEYDOWN lvkd = (NativeMethods.NMLVKEYDOWN)m.GetLParam(typeof(NativeMethods.NMLVKEYDOWN)); if (lvkd.wVKey == (short)Keys.Space) { ListViewItem focusedItem = FocusedItem; if (focusedItem != null) { bool check = !focusedItem.Checked; if (!VirtualMode) { foreach(ListViewItem item in SelectedItems) { if (item != focusedItem) { item.Checked = check; } } } } } } break; case NativeMethods.LVN_ODCACHEHINT: // tell the user to prepare the cache: NativeMethods.NMLVCACHEHINT cacheHint = (NativeMethods.NMLVCACHEHINT) m.GetLParam(typeof(NativeMethods.NMLVCACHEHINT)); OnCacheVirtualItems(new CacheVirtualItemsEventArgs(cacheHint.iFrom, cacheHint.iTo)); break; default: if (nmhdr->code == NativeMethods.LVN_GETDISPINFO) { // we use the LVN_GETDISPINFO message only in virtual mode if (this.VirtualMode && m.LParam != IntPtr.Zero) { // we HAVE to use unsafe code because of a bug in the CLR: WHIDBEY bug 20313 NativeMethods.NMLVDISPINFO_NOTEXT dispInfo= (NativeMethods.NMLVDISPINFO_NOTEXT) m.GetLParam(typeof(NativeMethods.NMLVDISPINFO_NOTEXT)); RetrieveVirtualItemEventArgs rVI = new RetrieveVirtualItemEventArgs(dispInfo.item.iItem); OnRetrieveVirtualItem(rVI); ListViewItem lvItem = rVI.Item; if (lvItem == null) { throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualItemRequired)); } lvItem.SetItemIndex(this, dispInfo.item.iItem); if ((dispInfo.item.mask & NativeMethods.LVIF_TEXT) != 0) { string text; if (dispInfo.item.iSubItem == 0) { text = lvItem.Text; // we want the item } else { if (lvItem.SubItems.Count <= dispInfo.item.iSubItem) { throw new InvalidOperationException(SR.GetString(SR.ListViewVirtualModeCantAccessSubItem)); } else { text = lvItem.SubItems[dispInfo.item.iSubItem].Text; // we want the sub item } } // use the buffer provided by the ComCtrl list view. if (dispInfo.item.cchTextMax <= text.Length) { text = text.Substring(0, dispInfo.item.cchTextMax - 1); } if (Marshal.SystemDefaultCharSize == 1) { // ANSI. Use byte byte[] buff = System.Text.Encoding.Default.GetBytes(text + "\0"); Marshal.Copy(buff, 0, dispInfo.item.pszText, text.Length + 1); } else { char[] buff = (text + "\0").ToCharArray(); Marshal.Copy(buff, 0, dispInfo.item.pszText, text.Length + 1); } } if ((dispInfo.item.mask & NativeMethods.LVIF_IMAGE) != 0 && lvItem.ImageIndex != -1) { dispInfo.item.iImage = lvItem.ImageIndex; } if ((dispInfo.item.mask & NativeMethods.LVIF_INDENT) != 0) { dispInfo.item.iIndent = lvItem.IndentCount; } /* [....]: Couldn't make this work. The dispInfo.item.iSubItem received for the subitems' text are invalid if ((dispInfo.item.mask & NativeMethods.LVIF_COLUMNS) != 0) { int cColumns = this.columnHeaders != null ? this.columnHeaders.Length : 0; dispInfo.item.cColumns = cColumns; if (cColumns > 0) { dispInfo.item.puColumns = Marshal.AllocHGlobal(cColumns * Marshal.SizeOf(typeof(int))); int[] columns = new int[cColumns]; for (int c = 0; c < cColumns; c++) { columns[c] = c + 1; } Marshal.Copy(columns, 0, dispInfo.item.puColumns, cColumns); } } */ /* [....]: VirtualMode and grouping seem to be incompatible. dispInfo.item.mask never includes NativeMethods.LVIF_GROUPID. Besides, trying to send LVM_ENABLEGROUPVIEW to the listview fails in virtual mode. if (this.GroupsEnabled && (dispInfo.item.mask & NativeMethods.LVIF_GROUPID) != 0) { dispInfo.item.iGroupId = GetNativeGroupId(lvItem); #if DEBUG Debug.Assert(SendMessage(NativeMethods.LVM_ISGROUPVIEWENABLED, 0, 0) != IntPtr.Zero, "Groups not enabled"); Debug.Assert(SendMessage(NativeMethods.LVM_HASGROUP, dispInfo.item.iGroupId, 0) != IntPtr.Zero, "Doesn't contain group id: " + dispInfo.item.iGroupId.ToString(CultureInfo.InvariantCulture)); #endif } */ if ((dispInfo.item.stateMask & NativeMethods.LVIS_STATEIMAGEMASK) != 0) { dispInfo.item.state |= lvItem.RawStateImageIndex; } Marshal.StructureToPtr(dispInfo, (IntPtr) m.LParam, false); } } else if (nmhdr->code == NativeMethods.LVN_ODSTATECHANGED) { if (VirtualMode && m.LParam != IntPtr.Zero) { NativeMethods.NMLVODSTATECHANGE odStateChange = (NativeMethods.NMLVODSTATECHANGE) m.GetLParam(typeof(NativeMethods.NMLVODSTATECHANGE)); bool selectedChanged = (odStateChange.uNewState & NativeMethods.LVIS_SELECTED) != (odStateChange.uOldState & NativeMethods.LVIS_SELECTED); if (selectedChanged) { // we have to substract 1 from iTo due to an imbecility in the win32 ListView control // see vsWhidbey 275717 - especially the ListView_CalcMinMaxIndex method. // in Vista, 275717 is fixed in windows OS side, we have don't need to work around here any more. int iTo = odStateChange.iTo; if (!UnsafeNativeMethods.IsVista) { iTo--; } ListViewVirtualItemsSelectionRangeChangedEventArgs lvvisrce = new ListViewVirtualItemsSelectionRangeChangedEventArgs(odStateChange.iFrom, iTo, (odStateChange.uNewState & NativeMethods.LVIS_SELECTED) != 0); OnVirtualItemsSelectionRangeChanged(lvvisrce); } } } else if (nmhdr->code == NativeMethods.LVN_GETINFOTIP) { if (ShowItemToolTips && m.LParam != IntPtr.Zero) { NativeMethods.NMLVGETINFOTIP infoTip = (NativeMethods.NMLVGETINFOTIP) m.GetLParam(typeof(NativeMethods.NMLVGETINFOTIP)); ListViewItem lvi = Items[infoTip.item]; if (lvi != null && !string.IsNullOrEmpty(lvi.ToolTipText)) { // MSDN: // Setting the max width has the added benefit of enabling multiline // tool tips! // UnsafeNativeMethods.SendMessage(new HandleRef(this, nmhdr->hwndFrom), NativeMethods.TTM_SETMAXTIPWIDTH, 0, SystemInformation.MaxWindowTrackSize.Width); if (Marshal.SystemDefaultCharSize == 1) { // ANSI. Use byte. // we need to copy the null terminator character ourselves byte[] byteBuf = System.Text.Encoding.Default.GetBytes(lvi.ToolTipText + "\0"); Marshal.Copy(byteBuf, 0, infoTip.lpszText, Math.Min(byteBuf.Length, infoTip.cchTextMax)); } else { // UNICODE. Use char. // we need to copy the null terminator character ourselves char[] charBuf = (lvi.ToolTipText + "\0").ToCharArray(); Marshal.Copy(charBuf, 0, infoTip.lpszText, Math.Min(charBuf.Length, infoTip.cchTextMax)); } Marshal.StructureToPtr(infoTip, (IntPtr) m.LParam, false); } } } else if (nmhdr->code == NativeMethods.LVN_ODFINDITEM) { if (VirtualMode) { NativeMethods.NMLVFINDITEM nmlvif = (NativeMethods.NMLVFINDITEM) m.GetLParam(typeof(NativeMethods.NMLVFINDITEM)); if ((nmlvif.lvfi.flags & NativeMethods.LVFI_PARAM) != 0) { m.Result = (IntPtr) (-1); return; } bool isTextSearch = ((nmlvif.lvfi.flags & NativeMethods.LVFI_STRING) != 0) || ((nmlvif.lvfi.flags & NativeMethods.LVFI_PARTIAL) != 0); bool isPrefixSearch = (nmlvif.lvfi.flags & NativeMethods.LVFI_PARTIAL) != 0; string text = String.Empty; if (isTextSearch) { text = nmlvif.lvfi.psz; } Point startingPoint = Point.Empty; if ((nmlvif.lvfi.flags & NativeMethods.LVFI_NEARESTXY) != 0) { startingPoint = new Point(nmlvif.lvfi.ptX, nmlvif.lvfi.ptY); } SearchDirectionHint dir = SearchDirectionHint.Down; if ((nmlvif.lvfi.flags & NativeMethods.LVFI_NEARESTXY) != 0) { // We can do this because SearchDirectionHint is set to the VK_* dir = (SearchDirectionHint) nmlvif.lvfi.vkDirection; } int startIndex = nmlvif.iStart; if (startIndex >= this.VirtualListSize) { // we want to search starting from the last item. Wrap around the first item. startIndex = 0; } SearchForVirtualItemEventArgs sviEvent = new SearchForVirtualItemEventArgs( isTextSearch, isPrefixSearch, false, /* includeSubItemsInSearch */ text, startingPoint, dir, nmlvif.iStart); OnSearchForVirtualItem(sviEvent); if (sviEvent.Index != -1) { m.Result = (IntPtr) sviEvent.Index; } else { m.Result = (IntPtr) (-1); } } } break; } }
protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: WmReflectNotify(ref m); break; case NativeMethods.WM_LBUTTONDBLCLK: // Ensure that the itemCollectionChangedInMouseDown is not set // before processing the mousedown event. this.ItemCollectionChangedInMouseDown = false; CaptureInternal = true; WmMouseDown(ref m, MouseButtons.Left, 2); break; case NativeMethods.WM_LBUTTONDOWN: // Ensure that the itemCollectionChangedInMouseDown is not set // before processing the mousedown event. this.ItemCollectionChangedInMouseDown = false; WmMouseDown(ref m, MouseButtons.Left, 1); downButton = MouseButtons.Left; break; case NativeMethods.WM_LBUTTONUP: case NativeMethods.WM_RBUTTONUP: case NativeMethods.WM_MBUTTONUP: // see the mouse is on item // NativeMethods.LVHITTESTINFO lvhip = new NativeMethods.LVHITTESTINFO(); int index = GetIndexOfClickedItem(lvhip); if (!ValidationCancelled && listViewState[LISTVIEWSTATE_doubleclickFired] && index != -1) { listViewState[LISTVIEWSTATE_doubleclickFired] = false; OnDoubleClick(EventArgs.Empty); OnMouseDoubleClick(new MouseEventArgs(downButton, 2, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); } if (!listViewState[LISTVIEWSTATE_mouseUpFired]) { OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); listViewState[LISTVIEWSTATE_expectingMouseUp] = false; } this.ItemCollectionChangedInMouseDown = false; listViewState[LISTVIEWSTATE_mouseUpFired] = true; CaptureInternal = false; break; case NativeMethods.WM_MBUTTONDBLCLK: WmMouseDown(ref m, MouseButtons.Middle, 2); break; case NativeMethods.WM_MBUTTONDOWN: WmMouseDown(ref m, MouseButtons.Middle, 1); downButton = MouseButtons.Middle; break; case NativeMethods.WM_RBUTTONDBLCLK: WmMouseDown(ref m, MouseButtons.Right, 2); break; case NativeMethods.WM_RBUTTONDOWN: WmMouseDown(ref m, MouseButtons.Right, 1); downButton = MouseButtons.Right; break; case NativeMethods.WM_MOUSEMOVE: if (listViewState[LISTVIEWSTATE_expectingMouseUp] && !listViewState[LISTVIEWSTATE_mouseUpFired] && MouseButtons == MouseButtons.None) { OnMouseUp(new MouseEventArgs(downButton, 1, NativeMethods.Util.SignedLOWORD(m.LParam), NativeMethods.Util.SignedHIWORD(m.LParam), 0)); listViewState[LISTVIEWSTATE_mouseUpFired] = true; } CaptureInternal = false; base.WndProc(ref m); break; case NativeMethods.WM_MOUSEHOVER: if (HoverSelection) { base.WndProc(ref m); } else OnMouseHover(EventArgs.Empty); break; case NativeMethods.WM_NOTIFY: if(WmNotify(ref m)) { break; // we are done - skip default handling } else { goto default; //default handling needed } case NativeMethods.WM_SETFOCUS: base.WndProc(ref m); if (!this.RecreatingHandle && !this.ListViewHandleDestroyed) { // This means that we get a WM_SETFOCUS on the hWnd that was destroyed. // Don't do anything because the information on the previous hWnd is most likely // out of [....] w/ the information in our ListView wrapper. // See comment in vsw 451268. // We should set focus to the first item, // if none of the items are focused already. if (FocusedItem == null && Items.Count > 0) { Items[0].Focused = true; } } break; case NativeMethods.WM_MOUSELEAVE: // if the mouse leaves and then re-enters the ListView // ItemHovered events should be raised. prevHoveredItem = null; base.WndProc(ref m); break; case NativeMethods.WM_PAINT: base.WndProc(ref m); // win32 ListView - look for comments about vsWhidbey 243708 BeginInvoke(new MethodInvoker(this.CleanPreviousBackgroundImageFiles)); break; case NativeMethods.WM_PRINT: WmPrint(ref m); break; case NativeMethods.WM_TIMER: if (unchecked( (int) (long)m.WParam) != LVTOOLTIPTRACKING || !ComctlSupportsVisualStyles) { base.WndProc(ref m); } break; default: base.WndProc(ref m); break; }; }
private void WmNmClick(ref Message m) { // If we're checked, hittest to see if we're // on the check mark if (CheckBoxes) { Point pos = Cursor.Position; pos = PointToClientInternal(pos); NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); lvhi.pt_x = pos.X; lvhi.pt_y = pos.Y; int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi); if (displayIndex != -1 && (lvhi.flags & NativeMethods.LVHT_ONITEMSTATEICON) != 0) { ListViewItem clickedItem = Items[displayIndex]; if (clickedItem.Selected) { bool check = !clickedItem.Checked; if (!VirtualMode) { foreach(ListViewItem item in SelectedItems) { if (item != clickedItem) { item.Checked = check; } } } } } } }
private void WmNmDblClick(ref Message m) { // If we're checked, hittest to see if we're // on the item if (CheckBoxes) { Point pos = Cursor.Position; pos = PointToClientInternal(pos); NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); lvhi.pt_x = pos.X; lvhi.pt_y = pos.Y; int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi); if (displayIndex != -1 && (lvhi.flags & NativeMethods.LVHT_ONITEM) != 0) { ListViewItem clickedItem = Items[displayIndex]; clickedItem.Checked = !clickedItem.Checked; } } }
/// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.HitTest1"]/*' /> /// <devdoc> /// </devdoc> public ListViewHitTestInfo HitTest(int x, int y) { if (!this.ClientRectangle.Contains(x, y)) { return new ListViewHitTestInfo(null /*hitItem*/, null /*hitSubItem*/, ListViewHitTestLocations.None /*hitLocation*/); } NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); lvhi.pt_x = x; lvhi.pt_y = y; int iItem; if (this.View == View.Details) { iItem = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SUBITEMHITTEST, 0, lvhi)); } else { iItem = unchecked( (int) (long)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_HITTEST, 0, lvhi)); } ListViewItem item = (iItem == -1) ? null : Items[iItem]; ListViewHitTestLocations location = ListViewHitTestLocations.None; if (item == null && (NativeMethods.LVHT_ABOVE & lvhi.flags) == NativeMethods.LVHT_ABOVE) { location = (ListViewHitTestLocations)((MASK_HITTESTFLAG & lvhi.flags) | (int)ListViewHitTestLocations.AboveClientArea); } else if (item != null && (NativeMethods.LVHT_ONITEMSTATEICON & lvhi.flags) == NativeMethods.LVHT_ONITEMSTATEICON) { location = (ListViewHitTestLocations)((MASK_HITTESTFLAG & lvhi.flags) | (int)ListViewHitTestLocations.StateImage); } else { location = (ListViewHitTestLocations)lvhi.flags; } if (this.View == View.Details && item != null) { if (lvhi.iSubItem < item.SubItems.Count) { return new ListViewHitTestInfo(item, item.SubItems[lvhi.iSubItem], location); } else { return new ListViewHitTestInfo(item, null, location); } } else { return (new ListViewHitTestInfo(item, null, location)); } }
internal void GetSubItemAt(int x, int y, out int iItem, out int iSubItem) { NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); lvhi.pt_x = x; lvhi.pt_y = y; int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_SUBITEMHITTEST, 0, lvhi); if (index > -1) { iItem = lvhi.iItem; iSubItem = lvhi.iSubItem; } else { iItem = -1; iSubItem = -1; } }
/// <include file='doc\ListView.uex' path='docs/doc[@for="ListView.GetItemAt"]/*' /> /// <devdoc> /// Returns the current ListViewItem corresponding to the specific /// x,y co-ordinate. /// </devdoc> public ListViewItem GetItemAt(int x, int y) { NativeMethods.LVHITTESTINFO lvhi = new NativeMethods.LVHITTESTINFO(); lvhi.pt_x = x; lvhi.pt_y = y; int displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_HITTEST, 0, lvhi); ListViewItem li = null; if (displayIndex >= 0 && ((lvhi.flags & NativeMethods.LVHT_ONITEM) != 0)) li = Items[displayIndex]; return li; }
protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_PAINT: _isInWmPaintMsg = true; base.WndProc(ref m); _isInWmPaintMsg = false; break; case NativeMethods.WM_REFLECT_NOTIFY: var nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR)); if (nmhdr.code == -12) { // NM_CUSTOMDRAW if (_isInWmPaintMsg) { base.WndProc(ref m); } } else { base.WndProc(ref m); } break; case NativeMethods.WM_LBUTTONUP: case NativeMethods.WM_LBUTTONDOWN: { if (IsListViewGroupClickHandled((uint)m.LParam, MouseButtons.Left)) { return; } base.WndProc(ref m); break; } case NativeMethods.WM_RBUTTONUP: case NativeMethods.WM_RBUTTONDOWN: { if (IsListViewGroupClickHandled((uint)m.LParam, MouseButtons.Right)) { return; } base.WndProc(ref m); break; } default: base.WndProc(ref m); break; } bool IsListViewGroupClickHandled(uint lparam, MouseButtons button) { var info = new NativeMethods.LVHITTESTINFO { pt = NativeMethods.LParamToPOINT(lparam) }; var handleRef = new HandleRef(this, Handle); if (NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SUBITEMHITTEST, (IntPtr)(-1), ref info) == new IntPtr(-1)) { return(false); } if ((info.flags & NativeMethods.LVHITTESTFLAGS.LVHT_EX_GROUP_HEADER) == 0) { return(false); } foreach (ListViewGroup group in Groups) { var groupId = GetGroupId(group); if (info.iItem == groupId) { GroupMouseClick?.Invoke(this, new ListViewGroupMouseEventArgs(button, group, 1, info.pt.X, info.pt.Y, 0)); return(true); } } return(false); } }
public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, NativeMethods.LVHITTESTINFO lParam);