예제 #1
0
 /// <summary>
 /// Gets the column at the specified position
 /// </summary>
 /// <param name="p">Point in client coordinates</param>
 /// <returns>The nul zero based index of the column (-1 if failed)</returns>
 public int GetColumnAt(Point p)
 {
     APIsStructs.LVHITTESTINFO hittest = new APIsStructs.LVHITTESTINFO();
     hittest.pt = new APIsStructs.POINTAPI(PointToClient(MousePosition));
     APIsUser32.SendMessage(
         Handle,
         (Int32) APIsEnums.ListViewMessages.SUBITEMHITTEST,
         0,
         ref hittest);
     return(hittest.iSubItem);
 }
예제 #2
0
        /// <summary>
        /// WndProc
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            #region View messages
            if(false)
            {
                string val;
                val = Enum.GetName(typeof(APIsEnums.ListViewMessages), (APIsEnums.ListViewMessages) m.Msg);
                if(val != "" && val != null)
                    Debug.WriteLine(val);
                else
                {
                    val = Enum.GetName(typeof(APIsEnums.WindowMessages), (APIsEnums.WindowMessages) m.Msg);
                    if(val != "" && val != null)
                    Debug.WriteLine(val);
                }
                if(val != "" && val != null)
                    Debug.WriteLine(m.Msg.ToString());
                if(val == "LBUTTONDOWN")
                {
                    int a= 0;
                    a++;
                }
            }
            #endregion

            TreeListViewItem item = null; Rectangle rec;
            switch((APIsEnums.WindowMessages) m.Msg)
            {
                #region NOTIFY
                case APIsEnums.WindowMessages.NOTIFY:
                case (APIsEnums.WindowMessages) APIsEnums.ReflectedMessages.NOTIFY:
                    APIsStructs.NMHDR nmhdr = (APIsStructs.NMHDR) m.GetLParam(typeof(APIsStructs.NMHDR));
                    APIsStructs.NMHEADER nmheader =(APIsStructs.NMHEADER) m.GetLParam(typeof(APIsStructs.NMHEADER));
                    switch((APIsEnums.ListViewNotifications) nmhdr.code)
                    {
                        #region APIsEnums.ListViewNotifications.MARQUEEBEGIN
                        case APIsEnums.ListViewNotifications.MARQUEEBEGIN:
                            if((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
                                m.Result = (IntPtr)1;
                            else
                                _hasMarquee = true;
                            break;
                        #endregion
                        #region APIsEnums.ListViewNotifications.ITEMCHANGING
                        case APIsEnums.ListViewNotifications.ITEMCHANGING:
                            APIsStructs.NMLISTVIEW nmlistview = (APIsStructs.NMLISTVIEW) m.GetLParam(typeof(APIsStructs.NMLISTVIEW));
                            if(nmlistview.iItem < 0) break;
                            if((item = GetTreeListViewItemFromIndex(nmlistview.iItem)) == null) break;
                            bool cancel = false;
                            if(nmlistview.Select)
                            {
                                if(_selectionMark == null) _selectionMark = item;
                                else if(!_selectionMark.Visible) _selectionMark = item;
                                if(HasMarquee) item.Focused = true;
                            }
                            else if(nmlistview.UnSelect && HasMarquee)
                            {
                                if(item.NextVisibleItem != null)
                                    if(item.NextVisibleItem.Selected)
                                        item.NextVisibleItem.Focused = true;
                                if(item.PrevVisibleItem != null)
                                    if(item.PrevVisibleItem.Selected)
                                        item.PrevVisibleItem.Focused = true;
                            }
                            #region Select after dbl click
                            // Disable the selection after a double click (normaly, if the control scrolls after
                            // a collapse, the new item under the cursor is automatically selected...)
                            if(_dblclicktime.AddMilliseconds(500).CompareTo(DateTime.Now) > 0 &&
                                (nmlistview.Select || nmlistview.Focus) &&
                                FocusedItem != item)
                                cancel = true;
                            #endregion
                            #region Wrong Level Select
                            if(((APIsEnums.ListViewItemStates)nmlistview.uNewState & APIsEnums.ListViewItemStates.SELECTED) == APIsEnums.ListViewItemStates.SELECTED &&
                                MultiSelect)
                                if(SelectedIndices.Count > 0)
                                    if(GetTreeListViewItemFromIndex(nmlistview.iItem).Parent != SelectedItems[0].Parent)
                                        cancel = true;
                            #endregion
                            #region Check during selection
                            // Disable check boxes check when :
                            // - the Marquee selection tool is being used
                            // - the Ctrl or Shift keys are down
                            bool state = (nmlistview.uChanged & (uint)APIsEnums.ListViewItemFlags.STATE) == (uint)APIsEnums.ListViewItemFlags.STATE;
                            bool ctrlKeyDown = (ModifierKeys & Keys.Control) == Keys.Control;
                            bool shiftKeyDown = (ModifierKeys & Keys.Shift) == Keys.Shift;
                            if((nmlistview.Check || nmlistview.UnCheck) &&
                                (HasMarquee || ctrlKeyDown || shiftKeyDown))
                            {
            //									MessageBox.Show(this,
            //										"uChanged = " + nmlistview->uChanged.ToString() + "\n\n" +
            //										"uOld = " + nmlistview->uOldState.ToString() + "\n" +
            //										"uNew = " + nmlistview->uChanged.ToString() + "\n\n" +
            //										"OldCheck : " + (oldCheck ? "true" : "false") + "\n" +
            //										"NewCheck : " + (newCheck ? "true" : "false"));
                                cancel = true;
                            }
                            #endregion
                            if(cancel)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;
                        #endregion

                        #region APIsEnums.ListViewNotifications.BEGINLABELEDIT
                        case APIsEnums.ListViewNotifications.BEGINLABELEDIT:
                            // Cancel label edit if the message is sent just after a double click
                            if(_lastdoubleclick.AddMilliseconds(450) > DateTime.Now)
                            {
                                Message canceledit = Message.Create(Handle, (int) APIsEnums.ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero);
                                WndProc(ref canceledit);
                                m.Result = (IntPtr) 1;
                                return;
                            }
                            item = _lastitemclicked.Item;
                            item.EnsureVisible();
                            // Add subitems if needed
                            while(item.SubItems.Count-1 < _lastitemclicked.ColumnIndex) item.SubItems.Add("");
                            TreeListViewBeforeLabelEditEventArgs beforeed = new TreeListViewBeforeLabelEditEventArgs(
                                FocusedItem, _lastitemclicked.ColumnIndex, item.SubItems[_lastitemclicked.ColumnIndex].Text);
                            OnBeforeLabelEdit(beforeed);
                            if(beforeed.Cancel)
                            {
                                Message canceledit = Message.Create(Handle, (int) APIsEnums.ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero);
                                WndProc(ref canceledit);
                                m.Result = (IntPtr) 1;
                                return;
                            }
                            _inedit = true;
                            // Get edit handle
                            Message mess = Message.Create(Handle, (int)APIsEnums.ListViewMessages.GETEDITCONTROL, IntPtr.Zero, IntPtr.Zero);
                            WndProc(ref mess);
                            IntPtr edithandle = mess.Result;
                            _customedit = new CustomEdit(edithandle, this, beforeed.Editor);
                            _editeditem = new EditItemInformations(
                                FocusedItem, beforeed.ColumnIndex, FocusedItem.SubItems[beforeed.ColumnIndex].Text);
                            m.Result = IntPtr.Zero;
                            return;
                        #endregion
                        #region APIsEnums.ListViewNotifications.ENDLABELEDIT
                        case APIsEnums.ListViewNotifications.ENDLABELEDIT:
                            if(_customedit != null)
                                _customedit.HideEditControl();
                            _customedit = null;
                            _inedit = false;
                            _editeditem = new EditItemInformations();
                            m.Result = IntPtr.Zero;
                            return;
                        #endregion

                        #region CUSTOMDRAW
                        case (APIsEnums.ListViewNotifications) APIsEnums.NotificationMessages.CUSTOMDRAW:
                            base.WndProc(ref m);
                            CustomDraw(ref m);
                            return;
                        #endregion

                        #region BEGINSCROLL
                        case APIsEnums.ListViewNotifications.BEGINSCROLL:
                            _updating = true;
                            break;
                        #endregion
                        #region ENDSCROLL
                        case APIsEnums.ListViewNotifications.ENDSCROLL:
                            _updating = false;
                            // Disable display bug with vertical lines (slow...)
            //							if(ShowPlusMinus)
            //							{
            //								DrawPlusMinusItemsLines();
            //								DrawPlusMinusItems();
            //							}
                            break;
                        #endregion

                        #region APIsEnums.HeaderControlNotifications.BEGINDRAG
                        case (APIsEnums.ListViewNotifications) APIsEnums.HeaderControlNotifications.BEGINDRAG:
                            nmheader =(APIsStructs.NMHEADER) m.GetLParam(typeof(APIsStructs.NMHEADER));
                            if(nmheader.iItem == 0)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;
                        #endregion
                        #region APIsEnums.HeaderControlNotifications.ENDDRAG
                        case (APIsEnums.ListViewNotifications) APIsEnums.HeaderControlNotifications.ENDDRAG:
                            nmheader =(APIsStructs.NMHEADER) m.GetLParam(typeof(APIsStructs.NMHEADER));
                            // Get mouse position in header coordinates
                            IntPtr headerHandle = (IntPtr) APIsUser32.SendMessage(Handle, (int) APIsEnums.ListViewMessages.GETHEADER, IntPtr.Zero, IntPtr.Zero);
                            APIsStructs.POINTAPI pointapi = new APIsStructs.POINTAPI(MousePosition);
                            APIsUser32.ScreenToClient(headerHandle, ref pointapi);
                            // HeaderItem Rect
                            APIsStructs.RECT headerItemRect = new APIsStructs.RECT();
                            APIsUser32.SendMessage(headerHandle, (int)APIsEnums.HeaderControlMessages.GETITEMRECT, 0, ref headerItemRect);
                            int headerItemWidth = headerItemRect.right - headerItemRect.left;
                            // Cancel the drag operation if the first column is moved
                            // or destination is the first column
                            if(pointapi.x <= headerItemRect.left + headerItemWidth / 2 ||
                                nmheader.iItem == 0)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;
                        #endregion
                        #region APIsEnums.HeaderControlNotifications.TRACK / ENDTRACK
            //						case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.TRACK:
                        case (APIsEnums.ListViewNotifications)APIsEnums.HeaderControlNotifications.ENDTRACK:
                            Invalidate();
                            break;
                        #endregion
                    }
                    break;
                #endregion

                #region LBUTTONDOWN
                    // Cancel the click on checkboxes if the item is not "checkable"
                    case APIsEnums.WindowMessages.LBUTTONDOWN:
                        if(Columns.Count == 0) break;
                        // Set the clickeditem and column
                        int colclicked = GetColumnAt(MousePosition);
                        if(colclicked == -1) colclicked = 0;
                        item = GetItemAtFullRow(PointToClient(MousePosition));
                        _lastitemclicked = new EditItemInformations(item, colclicked, "");
                        if(_selectionMark == null || !_selectionMark.Visible) _selectionMark = item;
                        if(((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) != APIsEnums.KeyStatesMasks.SHIFT &&
                            !(((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.CONTROL) == APIsEnums.KeyStatesMasks.CONTROL &&
                            item.Parent != _selectionMark.Parent))
                            _selectionMark = item;
                        // Get where the mouse has clicked
                        APIsStructs.LVHITTESTINFO lvhittest = new APIsStructs.LVHITTESTINFO();
                        lvhittest.pt = new APIsStructs.POINTAPI(PointToClient(MousePosition));
                        APIsUser32.SendMessage(Handle, (Int32) APIsEnums.ListViewMessages.HITTEST, 0, ref lvhittest);
                        if(item == null) break;
                        // Plus / Minus click
                        if(item.GetBounds(TreeListViewItemBoundsPortion.PlusMinus).Contains(PointToClient(MousePosition)) &&
                            ShowPlusMinus && item.Items.Count > 0 &&
                            Columns[0].Width > (item.Level+1)*SystemInformation.SmallIconSize.Width)
                        {
                            Focus();
                            if(item.IsExpanded) item.Collapse();
                            else item.Expand();
                            OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, PointToClient(MousePosition).X, PointToClient(MousePosition).Y, 0));
                            return;
                        }
                        // Cancel mouse click if multiselection on a wrong item
                        if(SelectedIndices.Count > 0 &&
                            (((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) == APIsEnums.KeyStatesMasks.SHIFT ||
                            ((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.CONTROL) == APIsEnums.KeyStatesMasks.CONTROL) &&
                            MultiSelect)
                        {
                            if(_selectionMark.Parent == item.Parent &&
                                ((APIsEnums.KeyStatesMasks)(int)m.WParam & APIsEnums.KeyStatesMasks.SHIFT) == APIsEnums.KeyStatesMasks.SHIFT)
                            {
                                _updating = true;
                                SetSelectedItemsRange(item, _selectionMark);
                                // Prevent all item at the wrong level of being selected
                                m.WParam = (IntPtr) APIsEnums.KeyStatesMasks.CONTROL;
                                base.WndProc(ref m);
                                item.Selected = true;
                                _updating = false;
                                DrawSelectedItemsFocusCues();
                                return;
                            }
                        }
                        break;
                #endregion
                #region LBUTTONDBLCLK
                    // Disable this notification to remove the auto-check when
                    // the user double-click on an item and append the expand / collapse function
                case APIsEnums.WindowMessages.LBUTTONDBLCLK:
                    _lastdoubleclick = DateTime.Now;
                    if(FocusedItem != null)
                    {
                        item = FocusedItem;
                        bool doExpColl = false;
                        switch(ExpandMethod)
                        {
                            case TreeListViewExpandMethod.IconDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.Icon);
                                if(rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            case TreeListViewExpandMethod.ItemOnlyDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.ItemOnly);
                                if(rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            case TreeListViewExpandMethod.EntireItemDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.Entire);
                                if(rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            default:
                                break;
                        }
                        if(doExpColl)
                        {
                            _dblclicktime = DateTime.Now;
                            Cursor = Cursors.WaitCursor;
                            BeginUpdate();
                            if(item.IsExpanded) item.Collapse();
                            else item.Expand();
                            EndUpdate();
                            Cursor = Cursors.Default;
                        }
                    }
                    OnDoubleClick(new EventArgs());
                    return;
                #endregion
                #region MOUSEMOVE
                case APIsEnums.WindowMessages.MOUSEMOVE:
                    if((MouseButtons & MouseButtons.Left) != MouseButtons.Left && HasMarquee)
                        _hasMarquee = false;
                    break;
                #endregion
                #region UNICHAR, CHAR, KEYDOWN
                case APIsEnums.WindowMessages.UNICHAR:
                case APIsEnums.WindowMessages.CHAR:
                    CharPressed((char) m.WParam);
                    return;
                case APIsEnums.WindowMessages.KEYDOWN:
                    OnKeyDown(new KeyEventArgs((Keys)(int) m.WParam));
                    return;
                #endregion
                #region PAINT
                case APIsEnums.WindowMessages.PAINT:
                    if(InEdit && EditedItem.Item != null)
                    {
                        APIsStructs.RECT rect = new APIsStructs.RECT(
                            EditedItem.Item.GetBounds(ItemBoundsPortion.Entire));
                        APIsUser32.ValidateRect(Handle, ref rect);
                    }
                    base.WndProc(ref m);
                    DrawIntermediateStateItems();
                    DrawSelectedItemsFocusCues();
                    return;
                #endregion
                #region VSCROLL, HSCROLL, ENSUREVISIBLE
                case APIsEnums.WindowMessages.VSCROLL:
                case APIsEnums.WindowMessages.HSCROLL:
                case (APIsEnums.WindowMessages)APIsEnums.ListViewMessages.ENSUREVISIBLE:
                    if(!Scrollable)
                    {
                        m.Result = (IntPtr)0;
                        return;
                    }
                    break;
                #endregion
            }
            base.WndProc(ref m);
        }