Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Drawing Resizable Controls at Runtime

0.00/5 (No votes)
4 Mar 2008 1  
How to draw resizable controls at runtime
resizablecontrols.gif

Introduction

This article will show how to draw borders around graphical objects and place them on the form, so users can manipulate the objects by dragging them around or resizing the controls. I hope this helps someone.

Background

I am involved in a project in which one tiny aspect of the application is where end users can place various objects on the forms and manipulate their properties. The application was developed in Delphi and I was curious what it would take to do something similar in .NET.

Using the Code

First, define the size of the drag handle that will appear around the control.

const int DRAG_HANDLE_SIZE = 7;

The method to actually draw the borders and the drag handles is as follows:

/// <summary>
/// Draw a border and drag handles around the control, on mouse down and up.
/// </summary>
/// <param name=""sender"" ></param >
private void DrawControlBorder(object sender)
{
    Control control = (Control)sender;
    //define the border to be drawn, it will be offset by DRAG_HANDLE_SIZE / 2
    //around the control, so when the drag handles are drawn they will seem to be
    //connected in the middle.
    Rectangle Border = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE / 2, 
            control.Location.Y - DRAG_HANDLE_SIZE / 2), 
        new Size(control.Size.Width + DRAG_HANDLE_SIZE, 
            control.Size.Height + DRAG_HANDLE_SIZE));
    //define the 8 drag handles, that has the size of DRAG_HANDLE_SIZE
    Rectangle NW = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle N = new Rectangle(
        new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle NE = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y - DRAG_HANDLE_SIZE), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle W = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y + control.Height/2-DRAG_HANDLE_SIZE/2), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle E = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y + control.Height / 2 - DRAG_HANDLE_SIZE / 2), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle SW = new Rectangle(
        new Point(control.Location.X - DRAG_HANDLE_SIZE, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle S = new Rectangle(
        new Point(control.Location.X + control.Width / 2 - DRAG_HANDLE_SIZE/2, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));
    Rectangle SE = new Rectangle(
        new Point(control.Location.X + control.Width, 
            control.Location.Y + control.Height), 
        new Size(DRAG_HANDLE_SIZE, DRAG_HANDLE_SIZE));

    //get the form graphic
    Graphics g = this.CreateGraphics();
    //draw the border and drag handles
    ControlPaint.DrawBorder(g, Border, Color.Gray, ButtonBorderStyle.Dotted);
    ControlPaint.DrawGrabHandle(g, NW, true, true);
    ControlPaint.DrawGrabHandle(g, N, true, true);
    ControlPaint.DrawGrabHandle(g, NE, true, true);
    ControlPaint.DrawGrabHandle(g, W, true, true);
    ControlPaint.DrawGrabHandle(g, E, true, true);
    ControlPaint.DrawGrabHandle(g, SW, true, true);
    ControlPaint.DrawGrabHandle(g, S, true, true);
    ControlPaint.DrawGrabHandle(g, SE, true, true);
    g.Dispose();
}

Next, implement the various events of the Control object, for example, when I click on a control, I want a border and drag handles drawn around it, so in the MouseDown event:

private void control_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        this.Invalidate();  //unselect other control
        SelectedControl = (Control)sender;
        Control control = (Control)sender;
        mouseX = -e.X;
        mouseY = -e.Y;
        control.Invalidate();
        DrawControlBorder(sender);
        propertyGrid1.SelectedObject = SelectedControl;
    }  
}

Finally, to use it, create a control at runtime and have it subscribe to the various events, for example to create a button:

Button ctrl = new Button();
ctrl.Text = "New Button";
ctrl.Location = new Point(50, 50);
ctrl.MouseEnter += new EventHandler(control_MouseEnter);
ctrl.MouseLeave += new EventHandler(control_MouseLeave);
ctrl.MouseDown += new MouseEventHandler(control_MouseDown);
ctrl.MouseMove += new MouseEventHandler(control_MouseMove);
ctrl.MouseUp += new MouseEventHandler(control_MouseUp);
Controls.Add(ctrl);

That's it. When executed, you can move the objects around, resize them in all 8 directions.

Points of Interest

If you download the source code, you'll notice that I use a timer to track the movement of the cursor. I tried to use the MouseHover event of the form, but that executed only once when the cursor is over it or when it leaves one of the controls, and subsequently when the cursor is over one of the drag handles it will fail to recognize it. Using a timer does solve this problem, but if you have found a better way please let me know!

History

  • 3/4/2008: First released

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