Share via


WM_NCHITTEST and Resizable ToolStripDropDowns

Jim asks: Do you know of a way to make the ToolStripDropDown resizable by the user, similar to what the SizingGrip of a StatusStrip does for a form?

The sizing grip of status bars (and the resize handles of forms, etc) are typically done by responding to the WM_NCHITTEST message. By returning values like HTBOTTOM, HTBOTTOMRIGHT, you can suggest to the operating system that this area of the window is a sizing border. When the mouse is pressed, the cursor automatically switches over to a sizing cursor and the OS takes over the sizing.

   private class ResizableToolStripDropDown : ToolStripDropDown {
            public ResizableToolStripDropDown() {
                this.AutoSize = false;
            }
           
            private Rectangle BottomGripBounds {
                get {
                    Rectangle rect = ClientRectangle;
                    rect.Y = rect.Bottom - 4;
                    rect.Height = 4;
                    
                    return rect;
                }
            }
            private Rectangle BottomRightGripBounds {
                get {
                    Rectangle rect = BottomGripBounds;
                    rect.X = rect.Width - 4;
                    rect.Width = 4;

                    return rect;
                }
            }

            protected override void WndProc(ref Message m) {
                if (m.Msg == NativeMethods.WM_NCHITTEST) {
                    // fetch out X & Y out of the message
                    int x = NativeMethods.LOWORD(m.LParam);
                    int y = NativeMethods.HIWORD(m.LParam);

                    // convert to client coords
                    Point clientLocation = PointToClient(new Point(x, y));

                    // prefer bottom right check
                    if (BottomRightGripBounds.Contains(clientLocation)) {
                        m.Result = (IntPtr)NativeMethods.HTBOTTOMRIGHT;
                        return;
                    }
                    // the bottom check
                    if (BottomGripBounds.Contains(clientLocation)) {
                        m.Result = (IntPtr)NativeMethods.HTBOTTOM;
                        return;
                    }
                    // else, let the base WndProc handle it.
                   
                }
                base.WndProc(ref m);
            }
            internal class NativeMethods {
                internal const int WM_NCHITTEST = 0x0084,
                                 HTBOTTOM = 15,
                                 HTBOTTOMRIGHT = 17;
                internal static int HIWORD(int n) {
                    return (n >> 16) & 0xffff;
                }

                internal static int HIWORD(IntPtr n) {
                    return HIWORD(unchecked((int)(long)n));
                }

                internal static int LOWORD(int n) {
                    return n & 0xffff;
                }

                internal static int LOWORD(IntPtr n) {
                    return LOWORD(unchecked((int)(long)n));
                }

            }
        }

The next things you would need to consider:

In order to Render the “grip” effect, you can override the OnRenderToolStripBorder method in the ToolStripRenderer. Extra space can be added to the toolstrip dropdown’s border area by increasing the Padding property.

In order to control the minimum/maximum size, you would need to respond to the WM_GETMINMAXINFO message.