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

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

0.00/5 (No votes)
13 Sep 2007 1  
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.

//
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:

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 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