向winforms中的多个控件添加相同的扩展 [英] Adding same extensions to multiple controls in winforms

查看:18
本文介绍了向winforms中的多个控件添加相同的扩展的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向 PictureBoxLabelPanel 添加一些扩展,例如移动、调整大小、...,如下所示:

I want to add some extensions like move, resize,... to PictureBox, Label, Panel like this:

public class LiveControl: PictureBox
{
    private Point cur = new Point(0, 0);
    public LiveControl()
    {
        ResizeRedraw = true;
        MouseDown += (s, e) => { cur = new Point(e.X, e.Y); };
        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();
            }
        };
    }
    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;
}

无论如何,我是否应该像类一样编写它并为所有类继承它,还是应该像我为 PictureBox 编写的那样编写 3 个单独的类?

Is there anyway that I write it like a class and inherit it for all of them, or should I write 3 separate classes like the one I have written for the PictureBox?

推荐答案

您可以将逻辑封装在从 NativeWindow 类.通过这种方式,您无需为要移动/调整大小的每个控件创建派生类即可完成这项工作.

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.

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

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.

示例

在下面的示例中,我重构了您发布的代码.这样你就可以使用所有控件的代码而无需继承.

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);
        }
    }
}

注意

1- 为了能够将控件恢复到其正常状态(不可调整大小不可移动),最好使用方法而不是使用 lambda 分配事件处理程序.您需要取消事件处理程序以将控件恢复到其正常状态.为此,您需要调用辅助类的 DestroyHanlde 方法.

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- 我只是重构了发布的代码,使其可重用于控件,而无需实现所有控件的派生版本.但是您可以通过以下方式增强代码:

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:

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

  • 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- 如果您需要在控件上调用 SetStyle,您可以简单地使用 这篇文章 并这样称呼它:

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

这篇关于向winforms中的多个控件添加相同的扩展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆