Click here to Skip to main content
15,889,861 members
Articles / Programming Languages / C#
Article

GripPanel

Rate me:
Please Sign up or sign in to vote.
4.13/5 (7 votes)
18 Oct 20033 min read 89.2K   23   11
A WinForms Panel that shows a size grip when docked at the bottom of a form.

Introduction

This is not an earth-shattering new development but you might find a use for it in your toolbox.

It is simply a control derived from the standard Winforms Panel control that draws a sizing grip when the panel is docked at the bottom of a form.

Background

This control was written to get around a bug in Winforms that prevents controls anchored to the right and bottom of a form working correctly in a derived form.

I simply wanted a base form with OK and Cancel buttons anchored to the bottom right of the form but unfortunately, when a derived form was resized in the designer, the next compile moved the buttons to incorrect positions.

This is documented in Microsoft Knowledge Base Article 316560[1] but the workarounds are:-

  1. Do not resize the form in the designer. (Which is not convenient!)
  2. Change the modifier from private to protected. (Which my controls already were, so this is incorrect)

My solution to this problem was to add a panel, all docked to the bottom of the form, with the required buttons (and some empty labels to provide spacing) docked to the right within that panel. This worked fine but it means that the form sizing grip was no longer visible.

So I decided to write a derived Panel that would have a sizing grip! What should have been a simple 5-minute job left me burning the midnight oil determined to find out how to do this.

How it works

I used Lutz Roeder's excellent Reflector for .NET[2] to look into System.Windows.Forms.Dll to see how Microsoft did it for a form and I also found an article by Karl E. Peterson called "Get a Grip With SubClassing"[3] written for VB which does a similar thing.

The first part, drawing the size grip itself is easy. ControlPaint.DrawSizeGrip (part of WinForms) will draw a size grip of any size onto a Graphics object such as that provided in the PaintEventArgs parameter the OnPaint method.

The next bit was to make the cursor change shape and actually resize the form when the mouse pointer is over the size grip. To do this, I had to override the WndProc method and look for WM_NCHITTEST message. When this message is received, I check whether the mouse pointer is within the size grip and if so, basically lie to Windows and tell it that the mouse pointer is in the lower-right corner of a border of a resizable window. At this point, Windows takes over and does all that is necessary!

Finally, when the window is being resized, I need to invalidate the rectangle containing the size grip so that it will be redrawn and not leave 'bits' behind. At first, I Invalidated just the rectangle containing the grip but when the form was resized quickly, some bits were still left behind. Using Reflector again, I found that Microsoft took the easy option and Invalidated the whole control so I did the same!

Oh, and I also added a dividing line at the top of the panel using ControlPaint in OnPaint again. This is optional.

References

  1. Microsoft website
  2. http://www.aisto.com/roeder/dotnet/
  3. http://archive.devx.com/premier/mgznarch/vbpj/1999/06jun99/ap0699.pdf

Source code

Here is the source code in full:

C#
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace SimmoTech.Forms {
  /// <summary>
  /// This control works exactly the same as a normal
  /// panel but, if the panel is docked at the bottom of the form,
  /// then a sizing grip is added and a horizontal 3D line
  /// is added at the top of panel.
  /// </summary>
  public class GripPanel: Panel {

    private const int HTBOTTOMRIGHT = 17;
    private const int WM_NCHITTEST = 0x84;
    private const int WM_SIZE = 0x05;

    /// <summary>
    /// Catch some windows messages
    /// </summary>
    /// <param name="m"></param>
    protected override void WndProc(ref Message m) {

      // Only catch messages if the panel is docked to the bottom
      if (Dock == DockStyle.Bottom) {

        switch (m.Msg) {

          // If the panel is being resized then we
          // need to redraw its contents
          case WM_SIZE:
            Invalidate();
            break;

          // If the system is asking where the mouse pointer is,
          // we need to check whether it is over our sizing grip
          case WM_NCHITTEST:

            // Convert to client co-ordinates of parent
            Point p = FindForm().PointToClient(new Point((int) m.LParam));
            int x = p.X;
            int y = p.Y;
            Rectangle rect = Bounds;

            // Is the mouse pointer over our sizing group?
            // (Use 12 pixels rather than 16 otherwise
            // too large an area is checked)
            if (x >= rect.X + rect.Width - 12 && 
                x <= rect.X + rect.Width && 
                y >= rect.Y + rect.Height - 12 && 
                y <= rect.Y + rect.Height) {

              // Yes, so tell windows it is in the lower-right
              // corner of a border of a resizable window
              // Windows will then do the neccessary resizing
              m.Result = new IntPtr(HTBOTTOMRIGHT);
              return;
            }
            break;
        }
      }

      // Do the normal message handling
      base.WndProc(ref m);
    }

    /// <summary>
    /// Override to add the border line at the top
    /// of the panel and the size grip itself
    /// </summary>
    /// <param name="e"></param>
    protected override void OnPaint(PaintEventArgs e) {

      // Do the normal painting
      base.OnPaint(e);
      // Are we docked at the bottom?
      if (Dock == DockStyle.Bottom) {

          // Yes, so paint the adornments
          ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle,
                   Border3DStyle.Raised, Border3DSide.Top);
          ControlPaint.DrawSizeGrip(e.Graphics, BackColor, 
                   Width - 16, Height -16, 16, 16);
      }
    }
  }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Hunton Information Systems Ltd.
United Kingdom United Kingdom
Simon Hewitt is a freelance IT consultant and is MD of Hunton Information Systems Ltd.

He is currently looking for contract work in London.

He is happily married to Karen (originally from Florida, US), has a lovely daughter Bailey, and they live in Kings Langley, Hertfordshire, UK.

Comments and Discussions

 
QuestionOnly the GripPanel is resized Pin
Jeppe A.22-Oct-09 23:44
Jeppe A.22-Oct-09 23:44 
GeneralMinimum width Pin
jordanhammond20-Nov-03 10:55
jordanhammond20-Nov-03 10:55 
GeneralRe: Minimum width Pin
jordanhammond20-Nov-03 21:46
jordanhammond20-Nov-03 21:46 
GeneralRe: Minimum width Pin
jordanhammond20-Nov-03 22:33
jordanhammond20-Nov-03 22:33 
GeneralAdding panel text Pin
RudolfHenning21-Oct-03 20:32
RudolfHenning21-Oct-03 20:32 
GeneralRe: Adding panel text Pin
RudolfHenning21-Oct-03 20:38
RudolfHenning21-Oct-03 20:38 
GeneralDocking... Pin
mikasa20-Oct-03 3:57
mikasa20-Oct-03 3:57 
GeneralCool references! Pin
TeleStar19-Oct-03 7:46
TeleStar19-Oct-03 7:46 
QuestionSizing grip not visible? Pin
WeigeltRo19-Oct-03 6:57
WeigeltRo19-Oct-03 6:57 
AnswerRe: Sizing grip not visible? Pin
SimmoTech19-Oct-03 10:50
SimmoTech19-Oct-03 10:50 
GeneralRe: Sizing grip not visible? Pin
WeigeltRo20-Oct-03 6:41
WeigeltRo20-Oct-03 6:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.