Click here to Skip to main content
15,867,488 members
Articles / Multimedia / GDI+
Article

Runtime Control Resizer

Rate me:
Please Sign up or sign in to vote.
4.83/5 (15 votes)
19 Jan 2007CPOL5 min read 88.9K   3.7K   50   26
An unfinished class that allows for runtime resizing of controls.

Sample Image - rtcontrolresizer.jpg

Introduction

An unfinished, simple class I started to write in response to a recent post on the microsoft.public.dotnet.languages.vb newsgroup.

Background

Not too long ago, I was browsing the VB.NET newsgroup like I normally do, and ran across a question that stumped me. The question was on how to provide the ability to resize a control during runtime. It seemed fairly straightforward, so I fired up C# (forgetting which newsgroup I read the question in!) and started typing up a quick solution - and it failed.

So I spent more and more time tweaking this late at night, and got most things worked out. Eventually, the OP stated he found a solution and wrote a CodeProject article about it. "Ah hah," I said, "I'll do the same!". And so I quit working on the code, and figured this would at least get someone else started. (Maybe, I'll finish it later - who knows?)

The Principle Components

The User Control

Nothing too complex here. I just needed a control that would represent the little white boxes that "float" around the outside of the control to be resized. The main job of the control is to just change the mouse cursor based on the position of the control (top left, top, etc.).

The Controller Class

Here, things get a little more verbose, but still not too complex. In a few sentences, the controller class first creates the necessary resize boxes (the user controls) and places them around the target control. The rest of the class simply handles the mouse-move events, and resizes the target control based on the movement of the specific resize box.

The Resize Box's Code

First off, I created an enum that listed all the available positions (relative to the target) that the resize box could have. Then, of course, I used this enum as a parameter in the control's constructor.

C#
public enum BoxPosition
{
    Top,
    Bottom,
    Left,
    Right,
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight
}

public ResizeBox(BoxPosition position)
{
    InitializeComponent();
    this.Position = position;
}

OK, nothing complex there. Next up, I handled both the MouseEnter and MouseLeave events of the control in order to set the appropriate arrow cursor depending on the Position property (not shown) of the control. Sounds like a job for a switch statement to me!

C#
private void ResizeBox_MouseEnter(object sender, EventArgs e)
{
    switch (this.Position)
    {
        case BoxPosition.Top:
            this.Cursor = Cursors.SizeNS;
            break;
        case BoxPosition.Bottom:
            this.Cursor = Cursors.SizeNS;
            break;
        case BoxPosition.Left:
            this.Cursor = Cursors.SizeWE;
            break;
        case BoxPosition.Right:
            this.Cursor = Cursors.SizeWE;
            break;
        case BoxPosition.TopLeft:
            this.Cursor = Cursors.SizeNWSE;
            break;
        case BoxPosition.BottomRight:
            this.Cursor = Cursors.SizeNWSE;
            break;
        case BoxPosition.TopRight:
            this.Cursor = Cursors.SizeNESW;
            break;
        case BoxPosition.BottomLeft:
            this.Cursor = Cursors.SizeNESW;
            break;
        default:
            this.Cursor = Cursors.No;
            break;
    }
}

private void ResizeBox_MouseLeave(object sender, EventArgs e)
{
    this.Cursor = Cursors.Default;
}

That pretty much takes care of the juicy bits for the user control - like I said, it's pretty simple.

The Controller Class

First of all, I need to create some variables to represent the actual resize boxes I'll place around the target.

C#
private ResizeBox topBox;
private ResizeBox bottomBox;
private ResizeBox leftBox;
private ResizeBox rightBox;
private ResizeBox topLeftBox;
private ResizeBox topRightBox;
private ResizeBox bottomLeftBox;
private ResizeBox bottomRightBox;

In the constructor, the target control is passed as a parameter. I set this into a property, instantiate the ResizeBox objects, and map the the necessary events to the methods that will handle them. The constructor also provides an option to immediately show the resize handles.

C#
public ResizeControl(Control target, Boolean showResizeBoxes)
{
    this._Target = target;

    target.Parent.Paint += new PaintEventHandler(Parent_Paint);

    topBox = new ResizeBox(ResizeBox.BoxPosition.Top);
    bottomBox = new ResizeBox(ResizeBox.BoxPosition.Bottom);
    leftBox = new ResizeBox(ResizeBox.BoxPosition.Left);
    rightBox = new ResizeBox(ResizeBox.BoxPosition.Right);
    topLeftBox = new ResizeBox(ResizeBox.BoxPosition.TopLeft);
    topRightBox = new ResizeBox(ResizeBox.BoxPosition.TopRight);
    bottomLeftBox = new ResizeBox(ResizeBox.BoxPosition.BottomLeft);
    bottomRightBox = new ResizeBox(ResizeBox.BoxPosition.BottomRight);

    this.topLeftBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.topBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.topRightBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.leftBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.rightBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.bottomLeftBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.bottomBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
    this.bottomRightBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);

    this.topLeftBox.MouseMove += new MouseEventHandler(topLeftBox_MouseMove);
    this.topBox.MouseMove += new MouseEventHandler(topBox_MouseMove);
    this.topRightBox.MouseMove += new MouseEventHandler(topRightBox_MouseMove);
    this.leftBox.MouseMove += new MouseEventHandler(leftBox_MouseMove);
    this.rightBox.MouseMove += new MouseEventHandler(rightBox_MouseMove);
    this.bottomLeftBox.MouseMove += 
         new MouseEventHandler(bottomLeftBox_MouseMove);
    this.bottomBox.MouseMove += new MouseEventHandler(bottomBox_MouseMove);
    this.bottomRightBox.MouseMove += 
         new MouseEventHandler(bottomRightBox_MouseMove);

    if (showResizeBoxes)
        ShowResizeBoxes();
}

Next is the code for the main methods for the controller, the second of which you'll see is empty. Like I said, I never finished the class, just the main parts.

C#
public void ShowResizeBoxes()
{
    PositionTopLeftBox();
    PositionTopBox();
    PositionTopRightBox();
    PositionLeftBox();
    PositionRightBox();
    PositionBottomLeftBox();
    PositionBottomBox();
    PositionBottomRightBox();
    Target.Parent.Controls.Add(topBox);
    Target.Parent.Controls.Add(bottomBox);
    Target.Parent.Controls.Add(leftBox);
    Target.Parent.Controls.Add(rightBox);
    Target.Parent.Controls.Add(topLeftBox);
    Target.Parent.Controls.Add(topRightBox);
    Target.Parent.Controls.Add(bottomLeftBox);
    Target.Parent.Controls.Add(bottomRightBox);
}

public void HideResizeBoxes()
{

}

As you can see, the ShowResizeBoxes() starts out by calling the position commands for all of the resize boxes and then adding the controls to the parent of the target control. They're basically all the same, so I'll just post the code for one.

C#
private void PositionTopLeftBox()
{
    topLeftBox.Top = Target.Top - topLeftBox.Height - 1;
    topLeftBox.Left = Target.Left - topLeftBox.Width - 1;
}

As you saw above, the MouseDown events for all of the ResizeBoxes is mapped to the same method. This method just sets the mouse location point for tracking movement.

C#
private Point mouseLocation;

private void Boxes_MouseDown(object sender, MouseEventArgs e)
{
    mouseLocation.X = e.X;
    mouseLocation.Y = e.Y;
}

And now for the heart of the class, the methods that actually resize the target control. Let's take the top-box as an example:

First and foremost, we need to make sure the left mouse button was the one that was clicked, so we use a simple if block. Next, I set three variables:

C#
if (e.Button == MouseButtons.Left)
{
    Int32 newBoxTop = topBox.Top + (e.Y - mouseLocation.Y);
    Int32 oldTargetTop = Target.Top;
    Int32 newTargetHeight = Target.Height + 
         (Target.Top - (topBox.Top + topBox.Height + 1));

The first variable, newBoxTop, will be used to check whether the size of the control will increase or decrease in size. The second, oldTargetTop, just saves the current top value so later when we change the top value of the target, we will know how much we should increase/decrease the height value by. Finally, newTargetHeight is the value that the height value of the target will be after we resize it. I set it here so I can check its value to prevent the target from going below a certain size. The minimum height and width values, I had wanted to put in a property, but I was lazy and just hard-coded them in. Here's, the if block that makes sure we don't drop below the minimum size, and the code that sets the new values and re-positions the effected resize-boxes:

C#
if (newTargetHeight > 15 || newBoxTop <= topBox.Top)
{
    Target.Top = newBoxTop + topBox.Height + 1;
    Target.Height += (oldTargetTop - Target.Top);
    topBox.Top = newBoxTop;
    PositionTopLeftBox();
    PositionTopRightBox();
    PositionLeftBox();
    PositionRightBox();
}
Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
       Target.Top - 6, Target.Width + 12, Target.Height + 12));

Here's the code for the entire method:

C#
private void topBox_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Int32 newBoxTop = topBox.Top + (e.Y - mouseLocation.Y);
        Int32 oldTargetTop = Target.Top;
        Int32 newTargetHeight = Target.Height + 
              (Target.Top - (topBox.Top + topBox.Height + 1));
        
        if (newTargetHeight > 15 || newBoxTop <= topBox.Top)
        {
            Target.Top = newBoxTop + topBox.Height + 1;
            Target.Height += (oldTargetTop - Target.Top);
            topBox.Top = newBoxTop;
            PositionTopLeftBox();
            PositionTopRightBox();
            PositionLeftBox();
            PositionRightBox();
        }
        Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
               Target.Top - 6, Target.Width + 12, Target.Height + 12));
    }
}

The one call I didn't explain earlier is the Target.Parent.Invalidate(...) call. You see, I'm trapping the target's parent's Paint event in order to use some simple GDI+ to draw the dotted line connecting the ResizeBoxes.

C#
public void Parent_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    Pen pen = new Pen(Brushes.Black, 1);
    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
    g.DrawRectangle(pen, new Rectangle(Target.Left - 3, 
          Target.Top - 3, Target.Width + 6, Target.Height + 6));
}

And that pretty much sums up the class! Basically, the user control handles the cursors, and the mouse-move events handle the actual resizing of the target control and re-positioning the resize boxes. Then, invalidating the region containing the target control forces the updating of the dotted line.

Using the Class

Nothing complex here, just create an instance of the class and pass the control you want to be resizable to the constructor. Setting the ShowResizeBoxes to show them immediately, or just calling it manually. Also, since the class implements IDisposable, using blocks could come in handy since the Dispose methods calls the HideResizeBoxes method.

C#
new ResizeControl(this.button1, true);

ResizeControl rc = new ResizeControl(this.button1, false);
rc.ShowResizeBoxes();

using (new ResizeControl(this.button1, true))
{
    //Do whatever you want here
}

The Problems

Too many boxes!

The class doesn't work well when a control doesn't allow either the height or width property to be set. A good example of this is a single line textbox. Pass that as the target and then drag the bottom resize box down. You'll see what I mean!

Speedy Moves = Unpredictable!

The MouseMove/MouseDown events don't fire near often enough to track fast movements. As a result, the minimum height/width tests can be ignored on fast moves, causing super small controls that may not be recoverable in some cases. Also, quickly "growing" the control can cause missed events that mess up the GDI+ rectangle, and can also leave orphaned or misplaced resize boxes. It seems the boxes move, but the target never resizes and the other resize boxes don't reposition.

The Complete Code

Since I know a lot of people don't want to download a code file, for a quick look-see, I figured I'd include this:

C#
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

class ResizeControl : IDisposable
{
    #region "Private Controls"

    private ResizeBox topBox;
    private ResizeBox bottomBox;
    private ResizeBox leftBox;
    private ResizeBox rightBox;
    private ResizeBox topLeftBox;
    private ResizeBox topRightBox;
    private ResizeBox bottomLeftBox;
    private ResizeBox bottomRightBox;

    private class ResizeBox : UserControl
    {
        public enum BoxPosition
        {
            Top,
            Bottom,
            Left,
            Right,
            TopLeft,
            TopRight,
            BottomLeft,
            BottomRight
        }

        public ResizeBox(BoxPosition position)
        {
            InitializeComponent();
            this.Position = position;
        }

        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.BackColor = System.Drawing.Color.White;
            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.Name = "ResizeBox";
            this.Size = new System.Drawing.Size(6, 6);
            this.MouseEnter += 
                 new System.EventHandler(this.ResizeBox_MouseEnter);
            this.MouseLeave += 
                 new System.EventHandler(this.ResizeBox_MouseLeave);
            this.ResumeLayout(false);
        }

        private BoxPosition _Position = BoxPosition.Top;
        public BoxPosition Position
        {
            get
            {
                return _Position;
            }
            set
            {
                _Position = value;
            }
        }

        private void ResizeBox_MouseEnter(object sender, EventArgs e)
        {
            switch (this.Position)
            {
                case BoxPosition.Top:
                    this.Cursor = Cursors.SizeNS;
                    break;
                case BoxPosition.Bottom:
                    this.Cursor = Cursors.SizeNS;
                    break;
                case BoxPosition.Left:
                    this.Cursor = Cursors.SizeWE;
                    break;
                case BoxPosition.Right:
                    this.Cursor = Cursors.SizeWE;
                    break;
                case BoxPosition.TopLeft:
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                case BoxPosition.BottomRight:
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                case BoxPosition.TopRight:
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case BoxPosition.BottomLeft:
                    this.Cursor = Cursors.SizeNESW;
                    break;
                default:
                    this.Cursor = Cursors.No;
                    break;
            }
        }

        private void ResizeBox_MouseLeave(object sender, EventArgs e)
        {
            this.Cursor = Cursors.Default;
        }
    }

    #endregion

    #region "Public Methods"

    public ResizeControl(Control target, Boolean showResizeBoxes)
    {
        this._Target = target;

        target.Parent.Paint += new PaintEventHandler(Parent_Paint);

        topBox = new ResizeBox(ResizeBox.BoxPosition.Top);
        bottomBox = new ResizeBox(ResizeBox.BoxPosition.Bottom);
        leftBox = new ResizeBox(ResizeBox.BoxPosition.Left);
        rightBox = new ResizeBox(ResizeBox.BoxPosition.Right);
        topLeftBox = new ResizeBox(ResizeBox.BoxPosition.TopLeft);
        topRightBox = new ResizeBox(ResizeBox.BoxPosition.TopRight);
        bottomLeftBox = new ResizeBox(ResizeBox.BoxPosition.BottomLeft);
        bottomRightBox = new ResizeBox(ResizeBox.BoxPosition.BottomRight);

        this.topLeftBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.topBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.topRightBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.leftBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.rightBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.bottomLeftBox.MouseDown += 
             new MouseEventHandler(Boxes_MouseDown);
        this.bottomBox.MouseDown += new MouseEventHandler(Boxes_MouseDown);
        this.bottomRightBox.MouseDown += 
             new MouseEventHandler(Boxes_MouseDown);

        this.topLeftBox.MouseMove += 
             new MouseEventHandler(topLeftBox_MouseMove);
        this.topBox.MouseMove += new MouseEventHandler(topBox_MouseMove);
        this.topRightBox.MouseMove += 
             new MouseEventHandler(topRightBox_MouseMove);
        this.leftBox.MouseMove += new MouseEventHandler(leftBox_MouseMove);
        this.rightBox.MouseMove += new MouseEventHandler(rightBox_MouseMove);
        this.bottomLeftBox.MouseMove += 
             new MouseEventHandler(bottomLeftBox_MouseMove);
        this.bottomBox.MouseMove += 
             new MouseEventHandler(bottomBox_MouseMove);
        this.bottomRightBox.MouseMove += 
             new MouseEventHandler(bottomRightBox_MouseMove);

        if (showResizeBoxes)
            ShowResizeBoxes();
    }

    public void Parent_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        Pen pen = new Pen(Brushes.Black, 1);
        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
        g.DrawRectangle(pen, new Rectangle(Target.Left - 3, 
              Target.Top - 3, Target.Width + 6, Target.Height + 6));
    }

    public void ShowResizeBoxes()
    {
        PositionTopLeftBox();
        PositionTopBox();
        PositionTopRightBox();
        PositionLeftBox();
        PositionRightBox();
        PositionBottomLeftBox();
        PositionBottomBox();
        PositionBottomRightBox();
        Target.Parent.Controls.Add(topBox);
        Target.Parent.Controls.Add(bottomBox);
        Target.Parent.Controls.Add(leftBox);
        Target.Parent.Controls.Add(rightBox);
        Target.Parent.Controls.Add(topLeftBox);
        Target.Parent.Controls.Add(topRightBox);
        Target.Parent.Controls.Add(bottomLeftBox);
        Target.Parent.Controls.Add(bottomRightBox);
    }

    public void HideResizeBoxes()
    {
        topBox.Visible = false;
    }

    void IDisposable.Dispose()
    {
        HideResizeBoxes();
    }

    #endregion

    #region "Move Event Handlers"

    private Point mouseLocation;

    private void Boxes_MouseDown(object sender, MouseEventArgs e)
    {
        mouseLocation.X = e.X;
        mouseLocation.Y = e.Y;
    }

    private void topLeftBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = topLeftBox.Top + (e.Y - mouseLocation.Y);
            Int32 oldTargetTop = Target.Top;
            Int32 newTargetHeight = Target.Height + 
                 (Target.Top - (topLeftBox.Top + topLeftBox.Height + 1));
            Int32 newBoxLeft = topLeftBox.Left + (e.X - mouseLocation.X);
            Int32 oldTargetLeft = Target.Left;
            Int32 newTargetWidth = Target.Width + (oldTargetLeft - Target.Left);

            if (newTargetWidth > 30 || newBoxLeft <= topLeftBox.Left)
            {
                Target.Left = newBoxLeft + topLeftBox.Width + 1;
                Target.Width += (oldTargetLeft - Target.Left);
                topLeftBox.Left = newBoxLeft;
                PositionTopLeftBox();
                PositionBottomLeftBox();
                PositionTopBox();
                PositionBottomBox();
                PositionLeftBox();
            }
            if (newTargetHeight > 15 || newBoxTop <= topBox.Top)
            {
                Target.Top = newBoxTop + topLeftBox.Height + 1;
                Target.Height += (oldTargetTop - Target.Top);
                topLeftBox.Top = newBoxTop;
                PositionTopLeftBox();
                PositionTopRightBox();
                PositionLeftBox();
                PositionRightBox();
                PositionTopBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void topBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = topBox.Top + (e.Y - mouseLocation.Y);
            Int32 oldTargetTop = Target.Top;
            Int32 newTargetHeight = Target.Height + 
                 (Target.Top - (topBox.Top + topBox.Height + 1));
            
            if (newTargetHeight > 15 || newBoxTop <= topBox.Top)
            {
                Target.Top = newBoxTop + topBox.Height + 1;
                Target.Height += (oldTargetTop - Target.Top);
                topBox.Top = newBoxTop;
                PositionTopLeftBox();
                PositionTopRightBox();
                PositionLeftBox();
                PositionRightBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void topRightBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = topRightBox.Top + (e.Y - mouseLocation.Y);
            Int32 oldTargetTop = Target.Top;
            Int32 newTargetHeight = Target.Height + 
                  (Target.Top - (topRightBox.Top + topRightBox.Height + 1));
            Int32 newBoxLeft = topRightBox.Left + (e.X - mouseLocation.X);
            Int32 newTargetWidth = topRightBox.Left - Target.Left - 1;

            if (newTargetWidth > 30 || newBoxLeft >= topRightBox.Left)
            {
                Target.Width = newTargetWidth;
                topRightBox.Left = newBoxLeft;
                PositionBottomRightBox();
                PositionTopBox();
                PositionBottomBox();
            }
            if (newTargetHeight > 15 || newBoxTop <= topRightBox.Top)
            {
                Target.Top = newBoxTop + topRightBox.Height + 1;
                Target.Height += (oldTargetTop - Target.Top);
                topRightBox.Top = newBoxTop;
                PositionTopLeftBox();
                PositionLeftBox();
                PositionRightBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void leftBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxLeft = leftBox.Left + (e.X - mouseLocation.X);
            Int32 oldTargetLeft = Target.Left;
            Int32 newTargetWidth = Target.Width + (oldTargetLeft - Target.Left);

            if (newTargetWidth > 30 || newBoxLeft <= leftBox.Left)
            {
                Target.Left = newBoxLeft + leftBox.Width + 1;
                Target.Width += (oldTargetLeft - Target.Left);
                leftBox.Left = newBoxLeft;
                PositionTopLeftBox();
                PositionBottomLeftBox();
                PositionTopBox();
                PositionBottomBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void rightBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxLeft = rightBox.Left + (e.X - mouseLocation.X);
            Int32 newTargetWidth = rightBox.Left - Target.Left - 1;

            if (newTargetWidth > 30 || newBoxLeft >= rightBox.Left)
            {
                Target.Width = newTargetWidth;
                rightBox.Left = newBoxLeft;
                PositionTopRightBox();
                PositionBottomRightBox();
                PositionTopBox();
                PositionBottomBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void bottomLeftBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = bottomLeftBox.Top + (e.Y - mouseLocation.Y);
            Int32 newTargetHeight = bottomLeftBox.Top - Target.Top - 1;
            Int32 newBoxLeft = bottomLeftBox.Left + (e.X - mouseLocation.X);
            Int32 oldTargetLeft = Target.Left;
            Int32 newTargetWidth = Target.Width + (oldTargetLeft - Target.Left);

            if (newTargetWidth > 30 || newBoxLeft <= bottomLeftBox.Left)
            {
                Target.Left = newBoxLeft + bottomLeftBox.Width + 1;
                Target.Width += (oldTargetLeft - Target.Left);
                bottomLeftBox.Left = newBoxLeft;
                PositionTopLeftBox();
                PositionTopBox();
                PositionBottomBox();
            }
            if (newTargetHeight > 15 || newBoxTop >= bottomLeftBox.Top)
            {
                Target.Height = newTargetHeight;
                bottomLeftBox.Top = newBoxTop;
                PositionBottomRightBox();
                PositionLeftBox();
                PositionRightBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void bottomBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = bottomBox.Top + (e.Y - mouseLocation.Y);
            Int32 newTargetHeight = bottomBox.Top - Target.Top - 1;

            if (newTargetHeight > 15 || newBoxTop >= bottomBox.Top)
            {
                Target.Height = newTargetHeight;
                bottomBox.Top = newBoxTop;
                PositionBottomLeftBox();
                PositionBottomRightBox();
                PositionLeftBox();
                PositionRightBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    private void bottomRightBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            Int32 newBoxTop = bottomRightBox.Top + (e.Y - mouseLocation.Y);
            Int32 newTargetHeight = bottomRightBox.Top - Target.Top - 1;
            Int32 newBoxLeft = bottomRightBox.Left + (e.X - mouseLocation.X);
            Int32 newTargetWidth = bottomRightBox.Left - Target.Left - 1;

            if (newTargetWidth > 30 || newBoxLeft >= bottomRightBox.Left)
            {
                Target.Width = newTargetWidth;
                bottomRightBox.Left = newBoxLeft;
                PositionTopRightBox();
                PositionTopBox();
                PositionBottomBox();
            }
            if (newTargetHeight > 15 || newBoxTop >= bottomRightBox.Top)
            {
                Target.Height = newTargetHeight;
                bottomRightBox.Top = newBoxTop;
                PositionBottomLeftBox();
                PositionLeftBox();
                PositionRightBox();
            }
            Target.Parent.Invalidate(new Rectangle(Target.Left - 6, 
                   Target.Top - 6, Target.Width + 12, Target.Height + 12));
        }
    }

    #endregion

    #region "Positioning Commands"

    private void PositionTopLeftBox()
    {
        topLeftBox.Top = Target.Top - topLeftBox.Height - 1;
        topLeftBox.Left = Target.Left - topLeftBox.Width - 1;
    }

    private void PositionTopBox()
    {
        topBox.Top = Target.Top - topBox.Height - 1;
        topBox.Left = Target.Left + (Target.Width / 2) - (topBox.Width / 2);
    }

    private void PositionTopRightBox()
    {
        topRightBox.Top = Target.Top - topRightBox.Height - 1;
        topRightBox.Left = Target.Left + Target.Width + 1;
    }

    private void PositionLeftBox()
    {
        leftBox.Top = Target.Top + (Target.Height / 2) - (leftBox.Height / 2);
        leftBox.Left = Target.Left - leftBox.Width - 1;
    }

    private void PositionRightBox()
    {
        rightBox.Top = Target.Top + (Target.Height / 2) - (rightBox.Height / 2);
        rightBox.Left = Target.Left + Target.Width + 1;
    }

    private void PositionBottomLeftBox()
    {
        bottomLeftBox.Top = Target.Top + Target.Height + 1;
        bottomLeftBox.Left = Target.Left - leftBox.Width - 1;
    }

    private void PositionBottomBox()
    {
        bottomBox.Top = Target.Top + Target.Height + 1;
        bottomBox.Left = Target.Left + 
                 (Target.Width / 2) - (bottomBox.Width / 2);
    }

    private void PositionBottomRightBox()
    {
        bottomRightBox.Top = Target.Top + Target.Height + 1;
        bottomRightBox.Left = Target.Left + Target.Width + 1;
    }

    #endregion

    #region "Properties"

    private Control _Target;
    public Control Target
    {
        get
        {
            if (_Target == null)
                _Target = new Control();
            return _Target;
        }
    }

    #endregion
}

History

  • 1/19/2007 - First release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
While young, at only 22 years of age, I constantly am trying to improve my programming skill set. I currently work for an IT technology leader as an ASP.NET/.NET developer in Columbus, Ohio. I was also awarded Microsoft MVP status for Visual Basic for the first time in 2008. It is a great honor to join the team of MVP's worldwide.

Apart from programming, I spend all my time with my lovely and supportive wife (who is carrying our first child). Besides from programming, you can also find me running around the virtual world of World of Warcraft.

Comments and Discussions

 
QuestionAlso want to Move the control at runtime Pin
Coder78620-May-19 1:36
Coder78620-May-19 1:36 
Questionmake it in VB 2010 Pin
ashwox2-Dec-14 17:23
ashwox2-Dec-14 17:23 
QuestionMove this control Pin
alireza taghizadeh7-May-13 0:26
alireza taghizadeh7-May-13 0:26 
GeneralMy vote of 5 Pin
saied golnejad11-Feb-13 1:52
saied golnejad11-Feb-13 1:52 
GeneralMy vote of 5 Pin
saied golnejad11-Feb-13 0:18
saied golnejad11-Feb-13 0:18 
GeneralMy vote of 5 Pin
Gilberto Alexandre2-Aug-10 7:28
Gilberto Alexandre2-Aug-10 7:28 
Questionwhere is the final one? Pin
AhmedGebaly8-Mar-09 2:46
AhmedGebaly8-Mar-09 2:46 
AnswerRe: where is the final one? Pin
Seth Rowe9-Mar-09 3:58
Seth Rowe9-Mar-09 3:58 
GeneralHmm: I downloaded and tried but... Pin
twesterd6-Jun-08 22:13
twesterd6-Jun-08 22:13 
GeneralRe: Hmm: I downloaded and tried but... Pin
twesterd6-Jun-08 22:18
twesterd6-Jun-08 22:18 
Ohh... and I see the handles "falling off" too.

WOW!

This is nowhere near ready. I like the idea, but... ummm... nooo!!!

I suggest reading up on GDI+ and work with the GraphicsPath directly.

Here is a great link:

http://www.bobpowell.net/[^]
GeneralRe: Hmm: I downloaded and tried but... Pin
Seth Rowe7-Jun-08 2:39
Seth Rowe7-Jun-08 2:39 
GeneralRe: Hmm: I downloaded and tried but... Pin
twesterd7-Jun-08 7:20
twesterd7-Jun-08 7:20 
GeneralRe: Hmm: I downloaded and tried but... Pin
Seth Rowe7-Jun-08 15:18
Seth Rowe7-Jun-08 15:18 
GeneralRe: Hmm: I downloaded and tried but... Pin
twesterd8-Jun-08 0:35
twesterd8-Jun-08 0:35 
GeneralRe: Hmm: I downloaded and tried but... Pin
Seth Rowe8-Jun-08 5:33
Seth Rowe8-Jun-08 5:33 
GeneralAmazing!!! totally different point of view Pin
Ricardo Casquete28-Apr-08 14:38
Ricardo Casquete28-Apr-08 14:38 
GeneralRe: Amazing!!! totally different point of view Pin
Seth Rowe29-Apr-08 1:09
Seth Rowe29-Apr-08 1:09 
GeneralRe: Amazing!!! totally different point of view Pin
Ricardo Casquete29-Apr-08 13:54
Ricardo Casquete29-Apr-08 13:54 
GeneralLosing resizing handles Pin
Ryan O'Neill29-Feb-08 9:03
Ryan O'Neill29-Feb-08 9:03 
GeneralDisposed Pin
negretrucci17-Aug-07 10:49
negretrucci17-Aug-07 10:49 
GeneralRefactored Pin
bmiller16-May-07 21:47
bmiller16-May-07 21:47 
GeneralCongrats on the first article... Pin
Ray Cassick19-Jan-07 17:20
Ray Cassick19-Jan-07 17:20 
GeneralRe: Congrats on the first article... Pin
Seth Rowe19-Jan-07 18:17
Seth Rowe19-Jan-07 18:17 
GeneralRe: Congrats on the first article... Pin
Ray Cassick19-Jan-07 18:39
Ray Cassick19-Jan-07 18:39 
NewsAlso see... Pin
Ravi Bhavnani19-Jan-07 15:28
professionalRavi Bhavnani19-Jan-07 15:28 

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.