在winforms中为多个控件添加相同的扩展名

我想添加一些扩展,如移动,resize,…到PictureBoxLabelPanel如下所示:

 public class LiveControl: PictureBox { private Point cur = new Point(0, 0); public LiveControl() { ResizeRedraw = true; MouseDown += (s, e) => { cur = new Point(eX, eY); }; MouseMove += (s, e) => { if (e.Button == MouseButtons.Left) { Control x = (Control)s; x.SuspendLayout(); x.Location = new Point(x.Left + eX - cur.X, x.Top + eY - cur.Y); x.ResumeLayout(); } }; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var rc = new Rectangle(this.ClientSize.Width - grab, this.ClientSize.Height - grab, grab, grab); ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc); } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == 0x84) { var pos = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16)); if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab) m.Result = new IntPtr(17); } } private const int grab = 16; } 

无论如何我是把它写成一个类并为它们inheritance它,或者我应该编写3个单独的类,就像我为PictureBox编写的类一样?

我认为使用T4文本模板可以解决您的问题。 如果您不熟悉,这些链接可能很有用:1。 代码生成和T4文本模板 2. 使用T4文本模板生成设计时代码

您可以将逻辑封装在派生自NativeWindow类的辅助类中。 这样,您可以在不为每个要移动/resize的控件创建派生类的情况下完成工作。

您可以将要扩展的控件传递给辅助类的构造函数,并将控制句柄分配给本机窗口。 然后覆盖本机窗口的WndProc将处理控件的消息。

还可以通过保持对在构造函数中传递的控件的引用并分配事件处理程序来实现控件的处理事件等其他内容。

在创建这样的本机窗口助手类之后,用法将是:

 var h1 = new LiveControlHelper(this.pictureBox1); var h2 = new LiveControlHelper(this.button1); 

或者,您可以在循环中将辅助对象用于容器的所有控件。

在下面的示例中,我重构了您发布的代码。 这样,您可以将代码用于所有控件,而无需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(eX, eY); }; control.MouseMove += (s, e) => { if (e.Button == MouseButtons.Left) { Control x = (Control)s; x.SuspendLayout(); x.Location = new Point(x.Left + eX - cur.X, x.Top + eY - 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); } } } 

注意

1-为了能够将控件恢复到正常状态(不可resize的不可移动),最好使用方法分配事件处理程序而不使用lambda。 您需要重新调整事件处理程序以将控件还原为其正常状态。 同样,你需要调用DestroyHanlde方法的helper类。

2-我只是重构了发布的代码,使其可以重用控件,而无需实现所有控件的派生版本。 但您可以通过以下方式增强代码:

  • 通过将m.Result设置为合适的值,可以使用曲面,边缘和控制角来移动控件并调整其大小。

  • 在控制上绘制抓斗边框/处理程序。

3-如果你需要在控件上调用SetStyle ,你可以简单地使用这篇文章中的扩展方法并以这种方式调用它:

 control.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw, true);