You can encapsulate the logic in a helper class deriving from NativeWindow
class. This way you can do the job without creating a derived class for each control which you want to move/resize.
You can pass the control which you want to extend to the constructor of helper class and assign your control handle to the native window. Then overriding WndProc
of native window will handle messages of the control.
Also other stuffs like handling event of the control is simply possible by keeping a reference to the control which you passed in constructor and assigning event handlers.
After creating such native window helper class the usage would be:
var h1 = new LiveControlHelper(this.pictureBox1);
var h2 = new LiveControlHelper(this.button1);
Or you can use the helper for all controls of a container in a loop.
Example
In below example, I refactored the code which you posted. This way you can use the code for all controls without need to inheritance.
using System;
using System.Drawing;
using System.Windows.Forms;
public class LiveControlHelper : NativeWindow
{
private Control control;
private Point cur = new Point(0, 0);
private const int grab = 16;
public LiveControlHelper(Control c)
{
control = c;
this.AssignHandle(c.Handle);
control.MouseDown += (s, e) => { cur = new Point(e.X, e.Y); };
control.MouseMove += (s, e) => {
if (e.Button == MouseButtons.Left) {
Control x = (Control)s;
x.SuspendLayout();
x.Location = new Point(x.Left + e.X - cur.X, x.Top + e.Y - cur.Y);
x.ResumeLayout();
}
};
control.Paint += (s, e) => {
var rc = new Rectangle(control.ClientSize.Width - grab,
control.ClientSize.Height - grab, grab, grab);
ControlPaint.DrawSizeGrip(e.Graphics, control.BackColor, rc);
};
control.Resize += (s, e) => { control.Invalidate(); };
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x84) {
var pos = control.PointToClient(new Point(m.LParam.ToInt32() & 0xffff,
m.LParam.ToInt32() >> 16));
if (pos.X >= control.ClientSize.Width - grab &&
pos.Y >= control.ClientSize.Height - grab)
m.Result = new IntPtr(17);
}
}
}
Note
1- To be able to revert the control to its normal state (non-resizable non-movable) it's better to assign event handlers using methods and not using lambda. You need to revome event handlers to revert the control to its normal state. Also to do so, you need to call DestroyHanlde
method of helper class.
2- I just refactored the posted code to make it reusable for controls without need to implement a derived version of all controls. But you can enhance the code by:
Enable moving the control and resizing it using surface, edges and corners of control by setting m.Result
to suitable values.
Draw grab borders/handlers on control.
3- If you need to call SetStyle
on control, you can simply use an extension method from this post and call it this way:
control.SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw, true);