Click here to Skip to main content
15,907,396 members
Articles / Programming Languages / C#
Tip/Trick

Move and Resize Controls on a Form at Runtime (With Mouse)

Rate me:
Please Sign up or sign in to vote.
4.98/5 (55 votes)
13 Jan 2014CPOL3 min read 218.8K   20.8K   61   50
Move and resize controls on a form at runtime (with mouse)
Image 1

Introduction

Sometimes, we want to move and resize controls in run time for example when we want to create some template for a form. There are some codes on the web for this but they cannot do both moving and resizing controls. Therefore, I write my own class on the basis of another CodeProject article.

Using this class, we can make resizeable and movable control with only one line of code:

C#
ControlMoverOrResizer.Init(button1);   

Really? Yes!! :)

Background

This class uses lambda expression in event handler assignment.

C#
internal static void Init(Control control, Control container)
{
    _moving = false;
    _resizing = false;
    _moveIsInterNal = false;
    _cursorStartPoint = Point.Empty;
    MouseIsInLeftEdge = false;
    MouseIsInLeftEdge = false;
    MouseIsInRightEdge = false;
    MouseIsInTopEdge = false;
    MouseIsInBottomEdge = false;
    WorkType = MoveOrResize.MoveAndResize;
    control.MouseDown += (sender, e) => StartMovingOrResizing(control, e);
    control.MouseUp += (sender, e) => StopDragOrResizing(control);
    control.MouseMove += (sender, e) => MoveControl(container, e);
}      

I write all fields, properties and methods static; therefore it is not needed to create an object of ControlMoverOrResizer class.

C#
internal class ControlMoverOrResizer
{
    private static bool _moving;
    private static Point _cursorStartPoint;
    private static bool _moveIsInterNal;
    private static bool _resizing;
    private static Size _currentControlStartSize;
    internal static bool MouseIsInLeftEdge { get; set; }
    internal static bool MouseIsInRightEdge { get; set; }
    internal static bool MouseIsInTopEdge { get; set; }
    internal static bool MouseIsInBottomEdge { get; set; }

    internal enum MoveOrResize ...

    internal static MoveOrResize WorkType { get; set; } 

    internal static void Init(Control control) ...

    internal static void Init(Control control, Control container) ...

    private static void UpdateMouseEdgeProperties(Control control, Point mouseLocationInControl) ...

    private static void UpdateMouseCursor(Control control) ...

    private static void StartMovingOrResizing(Control control, MouseEventArgs e) ...

    private static void MoveControl(Control control, MouseEventArgs e) ...

    private static void StopDragOrResizing(Control control) ...
}  

Alone not private method in class is init method. When sending a control (or two with its container) to init method, it will add related methods to 3 important control events.

C#
control.MouseDown += (sender, e) => StartMovingOrResizing(control, e);
control.MouseUp += (sender, e) => StopDragOrResizing(control);
control.MouseMove += (sender, e) => MoveControl(container, e); 

Now when user holds the mouse down on control, event calls the StartMovingOrResizing method, and this method will set movingMode or resizingMode of control:

C#
private static void StartMovingOrResizing(Control control, MouseEventArgs e)
{
    if (_moving || _resizing)
    {
        return;
    }
    if (WorkType!=MoveOrResize.Move &&
        (MouseIsInRightEdge || MouseIsInLeftEdge || MouseIsInTopEdge || MouseIsInBottomEdge))
    {
        _resizing = true;
        _currentControlStartSize = control.Size;
    }
    else if (WorkType!=MoveOrResize.Resize)
    {
        _moving = true;
        control.Cursor = Cursors.Hand;
    }
    _cursorStartPoint = new Point(e.X, e.Y);
    control.Capture = true;
}  

When user moves the mouse cursor on control MoveControl method will call, this method calls the UpdateMouseEdgeProperties and UpdateMouseCursor functions.

UpdateMouseEdgeProperties will check which cursor is on any edge of control and will set related properties:

C#
private static void UpdateMouseEdgeProperties(Control control, Point mouseLocationInControl)
{
	if (WorkType == MoveOrResize.Move)
	{
		return;
	}
	MouseIsInLeftEdge = Math.Abs(mouseLocationInControl.X) <= 2;
	MouseIsInRightEdge = Math.Abs(mouseLocationInControl.X - control.Width) <= 2;
	MouseIsInTopEdge = Math.Abs(mouseLocationInControl.Y ) <= 2;
	MouseIsInBottomEdge = Math.Abs(mouseLocationInControl.Y - control.Height) <= 2;
}

and UpdateMouseCursor functions will change mouse cursor if it is in the edge of control:

C#
private static void UpdateMouseCursor(Control control)
{
	if (WorkType == MoveOrResize.Move)
	{
		return;
	}
	if (MouseIsInLeftEdge )
	{
		if (MouseIsInTopEdge)
		{
			control.Cursor = Cursors.SizeNWSE;
		}
		else if (MouseIsInBottomEdge)
		{
			control.Cursor = Cursors.SizeNESW;
		}
		else
		{
			control.Cursor = Cursors.SizeWE;
		}
	}
	else if (MouseIsInRightEdge)
	{
		if (MouseIsInTopEdge)
		{
			control.Cursor = Cursors.SizeNESW;
		}
		else if (MouseIsInBottomEdge)
		{
			control.Cursor = Cursors.SizeNWSE;
		}
		else
		{
			control.Cursor = Cursors.SizeWE;
		}
	}
	else if (MouseIsInTopEdge || MouseIsInBottomEdge)
	{
		control.Cursor = Cursors.SizeNS;
	}
	else
	{
		control.Cursor = Cursors.Default;
	}
}

Now program will callback to MoveControl function and continue in this method. It will check _resizing field (this field will set when using pressDown mouse on age of control and keep it down).

If control is in resizing mode, that edge of control where cursor is on it just moves with cursor:

C#
if (_resizing)
{
	if (MouseIsInLeftEdge)
	{
		if (MouseIsInTopEdge)
		{
			control.Width -= (e.X - _cursorStartPoint.X);
			control.Left += (e.X - _cursorStartPoint.X); 
			control.Height -= (e.Y - _cursorStartPoint.Y);
			control.Top += (e.Y - _cursorStartPoint.Y);
		}
		else if (MouseIsInBottomEdge)
		{
			control.Width -= (e.X - _cursorStartPoint.X);
			control.Left += (e.X - _cursorStartPoint.X);
			control.Height = (e.Y - _cursorStartPoint.Y)                   
		             + _currentControlStartSize.Height; 
		}
		else
		{
			control.Width -= (e.X - _cursorStartPoint.X);
			control.Left += (e.X - _cursorStartPoint.X) ;
		}
	}
	else if (MouseIsInRightEdge)
	{
		if (MouseIsInTopEdge)
		{
			control.Width = (e.X - _cursorStartPoint.X) 
                            + _currentControlStartSize.Width;
			control.Height -= (e.Y - _cursorStartPoint.Y);
			control.Top += (e.Y - _cursorStartPoint.Y); 
 
		}
		else if (MouseIsInBottomEdge)
		{
			control.Width = (e.X - _cursorStartPoint.X) 
                            + _currentControlStartSize.Width;
			control.Height = (e.Y - _cursorStartPoint.Y) 
                            + _currentControlStartSize.Height;                    
		}
		else
		{
			control.Width = (e.X - _cursorStartPoint.X) 
                           +_currentControlStartSize.Width;
		}
	}
	else if (MouseIsInTopEdge)
	{
		control.Height -= (e.Y - _cursorStartPoint.Y);
		control.Top += (e.Y - _cursorStartPoint.Y);
	}
	else if (MouseIsInBottomEdge)
	{
		control.Height = (e.Y - _cursorStartPoint.Y) 
                   + _currentControlStartSize.Height;                    
	}
	else
	{
		 StopDragOrResizing(control);
	}
}     

Else if control is in moving mode (control goes to moving mode when user presses mouse down inside of control and keeps it down), the position of control will move with cursor:

C#
else if (_moving)
{
	_moveIsInterNal = !_moveIsInterNal;
	if (!_moveIsInterNal)
	{
		int x = (e.X - _cursorStartPoint.X) + control.Left;
		int y = (e.Y - _cursorStartPoint.Y) + control.Top;
		control.Location = new Point(x, y);
	}
}

At last, when user releases the mouse, StopDragOrResizing method will be called and it will reset moving mode and resizing mode to false and update the cursor.

private static void StopDragOrResizing(Control control)
{
	_resizing = false;
	_moving = false;
	control.Capture = false;
	UpdateMouseCursor(control);
} 

Using the Code

For enable resizing and moving mode for a control, we just call init method in MoveAndResizeControls class in send control to it.

C#
MoveAndResizeControls.Init(button1); 

If we want to change container of control (for example, when control is filled in its container), we just send container as the second parameter.

C#
ControlMoverOrResizer.Init(button2,panel1); 

In some cases, we just want one of resizing or moving for controls in this case we just set the WorkType property in the ControlMoverOrResizer class with one of these values:

C#
internal enum MoveOrResize
{
	Move,
	Resize,
	MoveAndResize
}

In the demo example that is uploaded here, controls can be moved and resized by mouse. Also, a combobox is in demo form who will help you select worktype ("move", "resize" or "move and resize").

C#
using System;
using System.Windows.Forms;
using ControlManager;
namespace MoveAndResizeControls
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ControlMoverOrResizer.Init(button1);
            ControlMoverOrResizer.Init(groupBox1);
            ControlMoverOrResizer.Init(textBox1);
            ControlMoverOrResizer.Init(button2,panel1);
            comboBox1.SelectedIndex = 0;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (comboBox1.SelectedIndex)
            {
                case 0:
                    ControlMoverOrResizer.WorkType=ControlMoverOrResizer.MoveOrResize.MoveAndResize;
                    break;
                case 1:
                    ControlMoverOrResizer.WorkType = ControlMoverOrResizer.MoveOrResize.Move;
                    break;
                case 2:
                    ControlMoverOrResizer.WorkType = ControlMoverOrResizer.MoveOrResize.Resize;
                    break;
            }
        }
    }
}    

Points of Interest

If you want to save and load changes, you can use these methods:

  • GetSizeAndPositionOfControlsToString
  • SetSizeAndPositionOfControlsFromString

This is form after move and resize controls:

Image 2

My sincere thanks for your time and consideration.
Best wishes.

History

  • 2014/01/10: As of publication, version 1.0.0.0
  • 2014/02/09: As of update, version 1.1.0.0

License

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


Written By
Software Developer (Senior)
Iran (Islamic Republic of) Iran (Islamic Republic of)
I enjoy learning new things everyday.

"It’s the principle of reaping huge rewards from a series of small, smart choices. Success is earned in the moment to moment decisions that in themselves make no visible difference whatsoever, but the accumulated compounding effect is profound." Darren Hardy

Comments and Discussions

 
AnswerRe: Thanks Pin
seyyed hamed monem11-Jul-14 12:06
professionalseyyed hamed monem11-Jul-14 12:06 
GeneralRe: Thanks Pin
Skynet197016-Jul-14 22:55
Skynet197016-Jul-14 22:55 
QuestionGreat...Thank you! Pin
revitarkitek22-May-14 14:06
revitarkitek22-May-14 14:06 
QuestionCapturing When a Move or Resize is Over Pin
Chris Hartnell24-Apr-14 5:12
Chris Hartnell24-Apr-14 5:12 
Questionhow to remove this feature from control Pin
MB Seifollahi9-Feb-14 9:47
professionalMB Seifollahi9-Feb-14 9:47 
AnswerRe: how to remove this feature from control Pin
seyyed hamed monem9-Feb-14 22:43
professionalseyyed hamed monem9-Feb-14 22:43 
GeneralRe: how to remove this feature from control Pin
MB Seifollahi10-Feb-14 0:04
professionalMB Seifollahi10-Feb-14 0:04 
AnswerRe: how to remove this feature from control Pin
Code_Novice2-Mar-16 11:46
Code_Novice2-Mar-16 11:46 
I was also originally having a lot of difficulties stopping the events once they were initialized for my controls in my app but I have come up with what I believe to be a pretty nice solution.

I am new to coding however dissecting this bit of code was a learning experience and in my opinion a must for new aspiring coders if they are wishing to learn Delegates, Events and Lambda expressions. I see here that the original poster added an End method which simply updates the WorkType enum but this doesn't actually stop the events from running in the background. I believe my way of stopping/shutting off this functionality by Unsubscribing from the events should be added to the original code as it's working beautifully in my WinForms app. This code was awesome to begin with and I'm thankful I found it here on Code Project. See my additions to the code below.

In order for your code to reference back to the original events you need an object that contains those events to reference back to. To accomplish this I took out ALL of the Static fields and made all of the fields Private except for the enum MoveOrResize and MoveOrResize WorkType. With this change I replaced the Static Init(Control control) function by adding a Class Constructor so that I would have the ability to new up each instance of the ControlMoverOrResizer class for each Control I wanted to add this functionality to. See below an example:

C#
internal enum MoveOrResize...

public MoveOrResize WorkType { get; set; }

// Constructor: Takes in a Control object
public ControlMoverOrResizer(Control control)
{
    Init(control, control);
}


The original code uses lambda expressions and as a newbie this was my first time ever seeing them. The way in which the events are subscribed leaves out a pointer to those events and once the events are Subscribed you are not provided with a way to Unsubscribe from them within the class.

First you must Declare the MouseEventHandlers globally within the ControlMoverOrResizer Class. I declared these just below the now private MouseEdge booleans like this:

C#
// Declare the Handlers globally so we can access them later in order to shut them off aka Unsubscribe the Event
private MouseEventHandler msDownHandler;
private MouseEventHandler msUpHandler;
private MouseEventHandler msMoveHandler;


Next I set these events to the Delegates in the same manner as seyyed hamed monem did in the original code however I am not Subscribing these events just yet. The events are now pointers to their corresponding Delegate (From what I know this is true however I could be slightly incorrect as I'm still learning this stuff). I accomplish this within the Init(Control control, Control container) method like this:

C#
msDownHandler = (sender, e) => StartMovingOrResizing(control, e);
msUpHandler = (sender, e) => StopDragOrResizing(control);
msMoveHandler = (sender, e) => MoveControl(container, e);


Also within the same Init() method I now Subscribe the events to the handlers like this:

C#
control.MouseDown += msDownHandler; // Uses StartMovingOrResizing
control.MouseUp += msUpHandler;     // Uses StopDragOrResizing
control.MouseMove += msMoveHandler; // Uses MoveControl


Lastly I created a method that can be used just like the Init() method only it turns off the events for the control provided to it. I struggled with a name for this method but ended up simply calling it StopMove():

C#
internal void StopMove(Control control)
{
     // Unsubscribe from these events using the original Handler
     control.MouseDown -= msDownHandler;
     control.MouseUp -= msUpHandler;
     control.MouseMove -= msMoveHandler;
}


So now you have both a way to turn the functionality On and Off.

Turn On:

C#
// Global reference to moverResizer
ControlMoverOrResizer moverResizer;

// Using the Class Constructor pass in a Control object to create a new instance of a ControlMoverOrResizer object
moverResizer = new ControlMoverOrResizer(Control);


Turn Off:

C#
moverResizer.StopMove(Control);


I hope this helps! And please... let me know if I'm wrong about the terminology I used to describe items such as the Events, Delegates and Handlers. Other improvements suggestions are of course welcome.

modified 3-Mar-16 18:35pm.

QuestionAdd Sizing handles to selected controls Pin
Saintniyi19-Jan-14 1:30
Saintniyi19-Jan-14 1:30 
AnswerRe: Add Sizing handles to selected controls Pin
seyyed hamed monem20-Jan-14 1:00
professionalseyyed hamed monem20-Jan-14 1:00 
AnswerRe: Add Sizing handles to selected controls Pin
Member 276569115-Jan-15 2:19
Member 276569115-Jan-15 2:19 
BugMove and resize controls on a form at runtime (with drag and drop) Pin
Saintniyi17-Jan-14 2:33
Saintniyi17-Jan-14 2:33 
GeneralRe: Move and resize controls on a form at runtime (with drag and drop) Pin
Saintniyi17-Jan-14 4:43
Saintniyi17-Jan-14 4:43 
AnswerRe: Move and resize controls on a form at runtime (with drag and drop) Pin
seyyed hamed monem18-Jan-14 5:50
professionalseyyed hamed monem18-Jan-14 5:50 
GeneralRe: Move and resize controls on a form at runtime (with drag and drop) Pin
Igormrcl27-Mar-14 4:03
Igormrcl27-Mar-14 4:03 
GeneralRe: Move and resize controls on a form at runtime (with drag and drop) Pin
PCBuilder24-Apr-14 6:31
PCBuilder24-Apr-14 6:31 
SuggestionSave the change Pin
Cosmic_Spy11-Jan-14 21:43
Cosmic_Spy11-Jan-14 21:43 
AnswerRe: Save the change Pin
seyyed hamed monem12-Jan-14 3:05
professionalseyyed hamed monem12-Jan-14 3:05 

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.