protected override void WndProc(ref Message m)
        {
            var message      = m;
            var groupHitInfo = new Lazy <ListViewGroupHitInfo>(() => GetGroupHitInfo(message));

            switch (m.Msg)
            {
            case NativeMethods.WM_LBUTTONUP when groupHitInfo.Value?.IsCollapseButton == true:
                DefWndProc(ref m);     // collapse / expand by clicking button in group header
                break;

            case NativeMethods.WM_PAINT:
                _isInWmPaintMsg = true;
                base.WndProc(ref m);
                _isInWmPaintMsg = false;
                break;

            case NativeMethods.WM_REFLECT_NOTIFY when IsCustomDraw(m) && !_isInWmPaintMsg:
            case NativeMethods.WM_RBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: false) :
            case NativeMethods.WM_RBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: true) :
            case NativeMethods.WM_LBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: false) :
            case NativeMethods.WM_LBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: true) :
                break;

            default:
                base.WndProc(ref m);
                break;
            }

            bool IsGroupMouseEventHandled(ListViewGroupHitInfo hitInfo, MouseButtons button, bool isDown)
            {
                if (hitInfo == null)
                {
                    return(false);
                }

                var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0);

                if (isDown)
                {
                    GroupMouseDown?.Invoke(this, eventArgs);
                }
                else
                {
                    GroupMouseUp?.Invoke(this, eventArgs);
                }

                return(eventArgs.Handled);
            }

            bool IsCustomDraw(Message msg)
            {
                var nmhdr = (NativeMethods.NMHDR)msg.GetLParam(typeof(NativeMethods.NMHDR));

                return(nmhdr.code == NativeMethods.NM_CUSTOMDRAW);
            }
        }
Esempio n. 2
0
        protected override void WndProc(ref Message m)
        {
            var message = m;

            switch (m.Msg)
            {
            case WM_LBUTTONUP when GetGroupHitInfo(message.LParam.ToPoint())?.IsCollapseButton == true:
                DefWndProc(ref m);     // collapse / expand by clicking button in group header

                break;

            case LVM_INSERTGROUP:
                base.WndProc(ref m);
                HandleAddedGroup(m);
                break;

            case WM_RBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Right, isDown: false) :
            case WM_RBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Right, isDown: true) :
            case WM_LBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Left, isDown: false) :
            case WM_LBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Left, isDown: true) :
                break;

            default:
                HandleScroll(m);
                base.WndProc(ref m);
                break;
            }

            void HandleScroll(Message msg)
            {
                ScrollEventType type;
                int?            newValue = null;

                switch (msg.Msg)
                {
                case WM_VSCROLL:
                    type     = (ScrollEventType)LowWord(msg.WParam.ToInt64());
                    newValue = HighWord(msg.WParam.ToInt64());
                    break;

                case WM_MOUSEWHEEL:
                    type = HighWord(msg.WParam.ToInt64()) > 0
                            ? ScrollEventType.SmallDecrement
                            : ScrollEventType.SmallIncrement;
                    break;

                case WM_KEYDOWN:
                    switch ((Keys)msg.WParam.ToInt32())
                    {
                    case Keys.Up:
                        type = ScrollEventType.SmallDecrement;
                        break;

                    case Keys.Down:
                        type = ScrollEventType.SmallIncrement;
                        break;

                    case Keys.PageUp:
                        type = ScrollEventType.LargeDecrement;
                        break;

                    case Keys.PageDown:
                        type = ScrollEventType.LargeIncrement;
                        break;

                    case Keys.Home:
                        type = ScrollEventType.First;
                        break;

                    case Keys.End:
                        type = ScrollEventType.Last;
                        break;

                    default:
                        return;
                    }

                    break;

                default:
                    return;
                }

                newValue ??= GetScrollPos(Handle, SB.VERT);
                Scroll?.Invoke(this, new ScrollEventArgs(type, newValue.Value));

                short LowWord(long number) =>
                unchecked ((short)(number & 0x0000ffff));

                short HighWord(long number) =>
                unchecked ((short)(number >> 16));
            }

            void HandleAddedGroup(Message msg)
            {
                if (!IsGroupStateSupported || !AllowCollapseGroups)
                {
                    return;
                }

                int groupIndex = GetGroupIndex();

                if (groupIndex < _minGroupInsertionIndex)
                {
                    return;
                }

                var listViewGroup = Groups[groupIndex];

                SetGroupState(listViewGroup, LVGS.Collapsible);
                Invalidate();

                int GetGroupIndex()
                {
                    // https://docs.microsoft.com/en-us/windows/desktop/controls/lvm-insertgroup
                    int index = msg.WParam.ToInt32();

                    if (index == -1)
                    {
                        // -1 because addition already happened
                        return(Groups.Count - 1);
                    }

                    return(index - 1 + _minGroupInsertionIndex);
                }
            }

            bool IsGroupMouseEventHandled(MouseButtons button, bool isDown)
            {
                var hitInfo = GetGroupHitInfo(message.LParam.ToPoint());

                if (hitInfo is null)
                {
                    return(false);
                }

                var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0);

                if (isDown)
                {
                    GroupMouseDown?.Invoke(this, eventArgs);
                }
                else
                {
                    GroupMouseUp?.Invoke(this, eventArgs);
                }

                return(eventArgs.Handled);
            }
        }
Esempio n. 3
0
        protected override void WndProc(ref Message m)
        {
            var message = m;

            switch (m.Msg)
            {
            case NativeMethods.WM_LBUTTONUP when GetGroupHitInfo(message.LParam.ToPoint())?.IsCollapseButton == true:
                DefWndProc(ref m);     // collapse / expand by clicking button in group header

                break;

            case NativeMethods.LVM_INSERTGROUP:
                base.WndProc(ref m);
                HandleAddedGroup(m);
                break;

            case NativeMethods.WM_PAINT:
                _isInWmPaintMsg = true;
                base.WndProc(ref m);
                _isInWmPaintMsg = false;
                break;

            case NativeMethods.WM_REFLECT_NOTIFY when IsCustomDraw(m) && !_isInWmPaintMsg:
            case NativeMethods.WM_RBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Right, isDown: false) :
            case NativeMethods.WM_RBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Right, isDown: true) :
            case NativeMethods.WM_LBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Left, isDown: false) :
            case NativeMethods.WM_LBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Left, isDown: true) :
                break;

            default:
                base.WndProc(ref m);
                break;
            }

            HandleScroll(m);

            void HandleScroll(Message msg)
            {
                ScrollEventType type;
                int?            newValue = null;

                switch (msg.Msg)
                {
                case NativeMethods.WM_VSCROLL:
                    type     = (ScrollEventType)(msg.WParam.ToInt32() & 0xffff);
                    newValue = msg.WParam.ToInt32() & 0x0000ffff;
                    break;

                case NativeMethods.WM_MOUSEWHEEL:
                    type = ScrollEventType.EndScroll;
                    break;

                case NativeMethods.WM_KEYDOWN:
                    switch ((Keys)msg.WParam.ToInt32())
                    {
                    case Keys.Up:
                        type = ScrollEventType.SmallDecrement;
                        break;

                    case Keys.Down:
                        type = ScrollEventType.SmallIncrement;
                        break;

                    case Keys.PageUp:
                        type = ScrollEventType.LargeDecrement;
                        break;

                    case Keys.PageDown:
                        type = ScrollEventType.LargeIncrement;
                        break;

                    case Keys.Home:
                        type = ScrollEventType.First;
                        break;

                    case Keys.End:
                        type = ScrollEventType.Last;
                        break;

                    default:
                        return;
                    }

                    break;

                default:
                    return;
                }

                newValue = newValue ?? NativeMethods.GetScrollPos(Handle, NativeMethods.SB_VERT);
                Scroll?.Invoke(this, new ScrollEventArgs(type, newValue.Value));
            }

            void HandleAddedGroup(Message msg)
            {
                if (!IsGroupStateSupported || !AllowCollapseGroups)
                {
                    return;
                }

                int groupIndex = GetGroupIndex();

                if (groupIndex < _minGroupInsertionIndex)
                {
                    return;
                }

                var listViewGroup = Groups[groupIndex];

                SetGrpState(listViewGroup, ListViewGroupState.Collapsible);
                Invalidate();

                int GetGroupIndex()
                {
                    // https://docs.microsoft.com/en-us/windows/desktop/controls/lvm-insertgroup
                    int index = msg.WParam.ToInt32();

                    if (index == -1)
                    {
                        // -1 because addition already happened
                        return(Groups.Count - 1);
                    }

                    return(index - 1 + _minGroupInsertionIndex);
                }

                void SetGrpState(ListViewGroup grp, ListViewGroupState state)
                {
                    int groupId = GetGroupId(grp);

                    if (groupId < 0)
                    {
                        groupId = Groups.IndexOf(grp) - _minGroupInsertionIndex;
                    }

                    var lvgroup = new NativeMethods.LVGROUP();

                    lvgroup.CbSize   = Marshal.SizeOf(lvgroup);
                    lvgroup.State    = state;
                    lvgroup.Mask     = NativeMethods.ListViewGroupMask.State;
                    lvgroup.IGroupId = groupId;

                    var handleRef = new HandleRef(this, Handle);

                    NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)groupId, ref lvgroup);
                }
            }

            bool IsGroupMouseEventHandled(MouseButtons button, bool isDown)
            {
                var hitInfo = GetGroupHitInfo(message.LParam.ToPoint());

                if (hitInfo == null)
                {
                    return(false);
                }

                var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0);

                if (isDown)
                {
                    GroupMouseDown?.Invoke(this, eventArgs);
                }
                else
                {
                    GroupMouseUp?.Invoke(this, eventArgs);
                }

                return(eventArgs.Handled);
            }

            bool IsCustomDraw(Message msg)
            {
                var nmhdr = (NativeMethods.NMHDR)msg.GetLParam(typeof(NativeMethods.NMHDR));

                return(nmhdr.code == NativeMethods.NM_CUSTOMDRAW);
            }
        }
Esempio n. 4
0
        protected override void WndProc(ref Message m)
        {
            var message      = m;
            var groupHitInfo = new Lazy <ListViewGroupHitInfo>(() => GetGroupHitInfo(message));

            switch (m.Msg)
            {
            case NativeMethods.WM_LBUTTONUP when groupHitInfo.Value?.IsCollapseButton == true:
                DefWndProc(ref m);     // collapse / expand by clicking button in group header
                break;

            case NativeMethods.LVM_INSERTGROUP:
                base.WndProc(ref m);
                HandleAddedGroup(m);
                break;

            case NativeMethods.WM_PAINT:
                _isInWmPaintMsg = true;
                base.WndProc(ref m);
                _isInWmPaintMsg = false;
                break;

            case NativeMethods.WM_REFLECT_NOTIFY when IsCustomDraw(m) && !_isInWmPaintMsg:
            case NativeMethods.WM_RBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: false) :
            case NativeMethods.WM_RBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: true) :
            case NativeMethods.WM_LBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: false) :
            case NativeMethods.WM_LBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: true) :
                break;

            default:
                base.WndProc(ref m);
                break;
            }

            void HandleAddedGroup(Message msg)
            {
                if (!IsGroupStateSupported || !AllowCollapseGroups)
                {
                    return;
                }

                int groupIndex = GetGroupIndex();

                if (groupIndex < _minGroupInsertionIndex)
                {
                    return;
                }

                var listViewGroup = Groups[groupIndex];

                SetGrpState(listViewGroup, ListViewGroupState.Collapsible);
                Invalidate();

                int GetGroupIndex()
                {
                    // https://docs.microsoft.com/en-us/windows/desktop/controls/lvm-insertgroup
                    int index = msg.WParam.ToInt32();

                    if (index == -1)
                    {
                        // -1 because addition already happened
                        return(Groups.Count - 1);
                    }

                    return(index - 1 + _minGroupInsertionIndex);
                }

                void SetGrpState(ListViewGroup grp, ListViewGroupState state)
                {
                    int groupId = GetGroupId(grp);

                    if (groupId < 0)
                    {
                        groupId = Groups.IndexOf(grp) - _minGroupInsertionIndex;
                    }

                    var lvgroup = new NativeMethods.LVGROUP();

                    lvgroup.CbSize   = Marshal.SizeOf(lvgroup);
                    lvgroup.State    = state;
                    lvgroup.Mask     = NativeMethods.ListViewGroupMask.State;
                    lvgroup.IGroupId = groupId;

                    var handleRef = new HandleRef(this, Handle);

                    NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)groupId, ref lvgroup);
                }
            }

            bool IsGroupMouseEventHandled(ListViewGroupHitInfo hitInfo, MouseButtons button, bool isDown)
            {
                if (hitInfo == null)
                {
                    return(false);
                }

                var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0);

                if (isDown)
                {
                    GroupMouseDown?.Invoke(this, eventArgs);
                }
                else
                {
                    GroupMouseUp?.Invoke(this, eventArgs);
                }

                return(eventArgs.Handled);
            }

            bool IsCustomDraw(Message msg)
            {
                var nmhdr = (NativeMethods.NMHDR)msg.GetLParam(typeof(NativeMethods.NMHDR));

                return(nmhdr.code == NativeMethods.NM_CUSTOMDRAW);
            }
        }