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.