【问题标题】:How can I use same mouse events in another form / user control?如何在另一个表单/用户控件中使用相同的鼠标事件?
【发布时间】:2019-05-25 21:43:20
【问题描述】:

我正在创建带有多个用户控件的 winforms c# 应用程序。它是没有任何边框的平面应用程序,因此移动窗口的唯一方法是使用鼠标控制事件。我在主窗口中使用了这部分代码,但我无法将它应用到任何其他用户控件中。我不想复制和粘贴所有用户控件,那么有什么方法可以使用它吗?

此代码在我的主窗体中工作,但是当我创建用户控件时,我无法访问这些控件,并且无法将它们连接到对象。

    private bool mouseDown;
    private Point lastLocation;

    private void _MouseDown(object sender, MouseEventArgs e)
    {
        mouseDown = true;
        lastLocation = e.Location;
    }

    private void _MouseMove(object sender, MouseEventArgs e)
    {
        if (mouseDown)
        {
            this.Location = new Point((this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
            this.Update();
        }
    }
    private void _MouseUp(object sender, MouseEventArgs e)
    {
        mouseDown = false;
    }

我可以制作事件处理程序/委托来解决它吗?

【问题讨论】:

  • 那么,你想通过鼠标点击/鼠标移动来移动窗口吗?难道你不能制作一个临时标题(标题栏)并在点击它时移动窗口吗?
  • 您可以从属性窗口的下拉列表中为相应的事件选择现有的事件处理程序(通过单击 Flash 图标切换到事件视图)。但是您也可以使用表单事件来执行此操作。然后,用户必须单击控件之间的空闲空间才能移动表单。
  • 递归地SEARCH为您感兴趣的表单中的所有控件类型,并动态地将它们的处理程序连接到您现有的方法。更改那些现有方法(主要是 _MouseMove)以将 sender 参数转换为控件并使用它而不是 this.

标签: c# winforms mouseevent eventhandler


【解决方案1】:

您能否再解释一下如何将 sender 参数转换为 控制?

当然:

private void _MouseMove(object sender, MouseEventArgs e)
{
    Control source = (Control)sender; // cast "sender" to a control
    if (mouseDown)
    {
        source.Location = new Point((source.Location.X - lastLocation.X) + e.X, (source.Location.Y - lastLocation.Y) + e.Y);
    }
}

现在,无论是事件“源”的控件都将被执行(而不是始终是带有“this”的表单)。

【讨论】:

  • 谢谢!你知道我如何从另一个用户控件访问它吗?因为它仍然是私有功能,所以我需要以某种方式委托它..
【解决方案2】:

这是一个帮助类,您可以将表单和控件类型传递给它,它将连接所有匹配的控件。在此示例中,所有按钮都已连接,因此您可以拖动它们。只需将“按钮”更改为您感兴趣的控件类型即可:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        this.WireControlsOfType<Button>();
    }      

    private void button1_Click(object sender, EventArgs e)
    {
        Form2 f2 = new Form2();
        f2.Show();
        f2.WireControlsOfType<Button>();
    }

}

不同文件中的辅助类:

public static class FormHelper
{

    public static void WireUserControl(this UserControl uc)
    {
        uc.MouseDown += _MouseDown;
        uc.MouseMove += _MouseMove;
        uc.MouseUp += _MouseUp;
    }

    public static void WireControlsOfType<T>(this Control sourceControl)
    {
        foreach(var ctl in sourceControl.RecursiveFindControlsByType<T>())
        {
            ctl.MouseDown += _MouseDown;
            ctl.MouseMove += _MouseMove;
            ctl.MouseUp += _MouseUp;
        }
    }

    // Code by Jon Skeet: https://stackoverflow.com/a/2055946/2330053
    public static IEnumerable<Control> RecursiveFindControlsByType<T>(this Control control)
    {
        foreach (Control c in control.Controls)
        {
            if (c is T)
            {
                yield return c;
            }

            if (c.Controls.Count > 0)
            {
                foreach (Control ctl in c.RecursiveFindControlsByType<T>())
                {
                    yield return ctl;
                }
            }
        }
    }

    private static bool mouseDown;
    private static Point lastLocation;

    private static void _MouseDown(object sender, MouseEventArgs e)
    {
        mouseDown = true;
        lastLocation = e.Location;
    }

    private static void _MouseMove(object sender, MouseEventArgs e)
    {
        Control source = (Control)sender;
        if (mouseDown)
        {
            source.Location = new Point((source.Location.X - lastLocation.X) + e.X, (source.Location.Y - lastLocation.Y) + e.Y);
        }
    }

    private static void _MouseUp(object sender, MouseEventArgs e)
    {
         mouseDown = false;
    }

}

请注意,我在 Load() 事件中使用“this”连接 Form1,但我也在 Click() 处理程序中为 Form2 的新实例演示它。

基于评论问题的附加帖子

根据您的 cmets,以下示例显示了 UserControl 内的按钮被连接起来以允许它们四处移动。 (我更改了 WireControlsOfType&lt;&gt; 方法以接受通用控件而不是 Form。) 默认 UserControl 属性中没有任何更改以允许这样做:

    private void button1_Click(object sender, EventArgs e)
    {
        panel1.Controls.Clear();

        UserControlA ucA = new UserControlA();
        ucA.Dock = DockStyle.Fill;         
        panel1.Controls.Add(ucA);
        ucA.WireControlsOfType<Button>();
    }

静态的 FormHelper 类是允许这种魔法的原因。它可以是它自己的类,不需要复制/关联任何 Forms/UserControls;实际上,它是独立于它们的,可以在自己的文件中。

如果您希望整个 UserControl 本身能够在其容器周围拖动,我在上面的帮助器类中添加了一个名为 WireUserControl() 的不同帮助器方法。所以下面的sn-p就是将多个UserControlA实例添加到panel1中,每一个都可以单独拖拽:

    private void button1_Click(object sender, EventArgs e)
    {
        UserControlA ucA = new UserControlA();        
        panel1.Controls.Add(ucA);
        ucA.WireUserControl();
    }

【讨论】:

  • 我觉得这对我的基本技能来说太复杂了。为了确保没有更简单的方法,我将尝试澄清我的意图。所以我有带有侧面板的主窗体窗口,可以在用户控件窗体之间切换。我实现了这部分代码来移动主窗口,并以这种形式将其与鼠标事件联系起来。我想对我拥有的每个用户控件做同样的事情。那么我应该将此功能复制并粘贴到用户控件并连接此事件,还是可以以某种方式编写一次并用于每个表单/用户控件?
  • 对不起,如果您已经回答了这个问题,也许我太新手无法实现它,我将继续复制和粘贴,直到我知道这里发生了什么:D
  • 对我来说仍然有点不清楚,但是...您是否想让控件您的 UserControls 能够被拖动? (这就是我要演示的内容)...或者您是否希望将 整个 UserControl(添加到您的主窗体中的任何一个)作为一个单元拖动?
  • 查看添加到主帖底部的编辑。希望这有助于理清思路并对您有用。
猜你喜欢
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-12
相关资源
最近更新 更多