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

Drag and Drop Windows/Form Controls (Design UI at Runtime)

Rate me:
Please Sign up or sign in to vote.
4.33/5 (24 votes)
13 Sep 2007CPOL2 min read 123.1K   9.4K   95   17
Enables user to design the user interface by moving all form controls to the desired place. It allows to move the control at execution time.
Screenshot - movableControls.jpg

Introduction

The source code of this article allows the user to provide a kind of user interface in which controls can be dragged and dropped on a form at the desired place. Clicking on Design Mode will enable the user to move all form controls by just clicking the mouse left button and dropping the control by leaving the mouse control. The good thing is that to enable the runtime dragging capability, there is no need to change the main form class or classes of controls. Everything is controlled using a separate class that has a small interface with the main form class.

Background

This article is totally based on Windows controls, mouse events, paint events and update regions.

Using the Code

A separate user control (draggableControls) is implemented. Just drag and drop that control on the Main Form from the toolbox. It would be invisible at runtime. This class has a DesignMode function that enables and disables runtime movement of all form controls by registering and unregistering event handlers of Mouse events. Look at the function given below, it is fully commented.

C#
//
public void DesignMode(bool Enable)
{
mainForm = TopLevelControl; //Take the handle of main form control
Control ctrl = mainForm.GetNextControl(null, true); //Get First Control
do
{ 
if(ctrl.Text!="Design Mode" && ctrl.Text!="Control Mode") //Leave two buttons
SetEvent(ctrl, Enable); // Register/Unregister Event Handler
ctrl = mainForm.GetNextControl(ctrl, true); //Get Next Control
}while( ctrl != null); 
if (Enable) //Register/Unregister main form paint events
{
mainForm.Paint += new PaintEventHandler(mainForm_Paint);
mainForm.MouseMove += new MouseEventHandler(mainForm_MouseMove);
mainForm.MouseUp += new MouseEventHandler(mainForm_MouseUp);
}else
{
mainForm.Paint -= new PaintEventHandler(mainForm_Paint);
mainForm.MouseMove -= new MouseEventHandler(mainForm_MouseMove);
mainForm.MouseUp -= new MouseEventHandler(mainForm_MouseUp);
}
}
//

Other important functions are mouse Events (up, down, move) and main form Paint Event. On the mouse down event, we store the control and control size. On the mouse move event, it shows the dummy image of the control and on mouse down, it places the control at that place.

In the OnPaint function, it shows the dummy image of the control. To stop flickering and to optimize graphics, it creates the control path and updates only the dummy image path.

The code of these functions are given below:

C#
void ctrl_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
//find out which control is being dragged
controlUnderDrag = mainForm.GetChildAtPoint(((Control)sender).Location + 
    new Size(e.Location.X, e.Location.Y));
if (controlUnderDrag != null)
{
mainForm.Capture = true; //capture mouse
mainForm.Cursor = Cursors.Hand; //change cursor
controlImage = new Rectangle(controlUnderDrag.Location, controlUnderDrag.Size);
//offset of mouse from control location
mouseOffset = new Size(e.Location.X, e.Location.Y); 
Rectangle tempRectangle = new Rectangle(controlImage.X - 2, 
    controlImage.Y - 2, controlImage.Width + 4, controlImage.Height + 4);
GraphicsPath myGraphicsPath = new GraphicsPath(); //path of rectangle area of control
myGraphicsPath.AddRectangle(tempRectangle);
System.Drawing.Region rgn = new Region(myGraphicsPath);
mainForm.Invalidate(rgn);
controlDragStarted = true;
} 
}
}
void mainForm_MouseMove(object sender, MouseEventArgs e)
{
if (controlDragStarted)
{
GraphicsPath myGraphicsPath = new GraphicsPath();
Rectangle tempRectangle = new Rectangle(controlImage.X - 2, controlImage.Y - 2, 
    controlImage.Width + 4, controlImage.Height + 4);
myGraphicsPath.AddRectangle(tempRectangle);
System.Drawing.Region rgn = new Region(myGraphicsPath);
controlImage = new Rectangle(e.Location.X - mouseOffset.Width, 
    e.Location.Y - mouseOffset.Height, controlImage.Width,
controlImage.Height);

mainForm.Invalidate(rgn);
myGraphicsPath.Dispose();
myGraphicsPath = new GraphicsPath();
rgn.Dispose();
tempRectangle = new Rectangle(controlImage.X - 2, controlImage.Y - 2, 
    controlImage.Width + 4, controlImage.Height + 4);
rgn = new Region(tempRectangle);
mainForm.Invalidate(rgn);
 }
}
void mainForm_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left && controlDragStarted)
{
controlDragStarted = false;
mainForm.Capture = false;
mainForm.Cursor = Cursors.Default;
GraphicsPath myGraphicsPath = new GraphicsPath();
Rectangle tempRectangle = new Rectangle(controlImage.X - 2, controlImage.Y - 2, 
    controlImage.Width + 4, controlImage.Height + 4);
myGraphicsPath.AddRectangle(tempRectangle);
System.Drawing.Region rgn = new Region(myGraphicsPath);
controlUnderDrag.Location = controlImage.Location;
controlImage.Height = 0; controlImage.Width = 0;
mainForm.Invalidate(rgn);
controlUnderDrag.Invalidate();
}
}
void mainForm_Paint(object sender, PaintEventArgs e)
{ 
if (controlImage != null && controlDragStarted)
{
e.Graphics.DrawRectangle(Pens.Green, controlImage);
}
}

Further Enhancements

Further enhancements like allowing to move only the selected controls, showing a different color dummy image while the control is moving can be done easily just by adding some properties in the DraggableControls class.

History

  • 14th September, 2007: Initial post

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)
India India
Vikas Maan is a software developer for last 4 years working on windows platform with multiple programming languages mainly VC++, C#.net etc.

Comments and Discussions

 
GeneralMDI Child Object Access Problem Pin
hakcay31-May-10 23:44
hakcay31-May-10 23:44 
GeneralDragg Multiple Control Pin
jazzyvishal12-Sep-08 0:00
jazzyvishal12-Sep-08 0:00 
GeneralRe: Dragg Multiple Control Pin
vikas maan24-Sep-08 17:56
vikas maan24-Sep-08 17:56 
GeneralProblem Using with MDI Pin
mnoorbash19-May-08 3:58
mnoorbash19-May-08 3:58 
GeneralRe: Problem Using with MDI Pin
Member 301963930-May-08 7:14
Member 301963930-May-08 7:14 
Hi,
sorry for late reply. Let me know what problem you are facing with MDI.

regards
Maan
GeneralRe: Problem Using with MDI Pin
tarikcorut11-Aug-09 3:22
tarikcorut11-Aug-09 3:22 
QuestionQuestion... dragging controls on a TabControl/TabPage Pin
Gary Butler6-Dec-07 9:20
Gary Butler6-Dec-07 9:20 
GeneralRe: Question... dragging controls on a TabControl/TabPage Pin
vikas maan8-Jan-08 18:42
vikas maan8-Jan-08 18:42 
QuestionRemember Last Setting Pin
prit_mahudha16-Oct-07 0:38
prit_mahudha16-Oct-07 0:38 
AnswerRe: Remember Last Setting Pin
vikas maan16-Oct-07 17:35
vikas maan16-Oct-07 17:35 
GeneralRe: Remember Last Setting Pin
prit_mahudha16-Oct-07 21:44
prit_mahudha16-Oct-07 21:44 
GeneralRe: Remember Last Setting Pin
vikas maan8-Jan-08 18:45
vikas maan8-Jan-08 18:45 
GeneralCustom Designer Pin
Dan Radu18-Sep-07 3:50
Dan Radu18-Sep-07 3:50 
GeneralRe: Custom Designer Pin
vikas maan19-Sep-07 18:03
vikas maan19-Sep-07 18:03 
GeneralNice try Pin
Praveen Nair (NinethSense)16-Sep-07 21:05
Praveen Nair (NinethSense)16-Sep-07 21:05 
GeneralRe: Nice try Pin
vikas maan19-Sep-07 18:03
vikas maan19-Sep-07 18:03 
GeneralInteresting Idea Pin
merlin98114-Sep-07 5:37
professionalmerlin98114-Sep-07 5:37 

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.