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:
private void DrawControlBorder(object sender)
{
Control control = (Control)sender;
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));
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));
Graphics g = this.CreateGraphics();
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();
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