【问题标题】:Pass-through mouse events to parent control将鼠标事件传递给父控件
【发布时间】:2010-10-07 12:36:25
【问题描述】:

环境:.NET Framework 2.0,VS 2008。

我正在尝试创建某些 .NET 控件(标签、面板)的子类,它将通过某些鼠标事件(MouseDownMouseMoveMouseUp)传递到其父控件(或者传递到顶部)级形式)。我可以通过在标准控件的实例中为这些事件创建处理程序来做到这一点,例如:

public class TheForm : Form
{
    private Label theLabel;

    private void InitializeComponent()
    {
        theLabel = new Label();
        theLabel.MouseDown += new MouseEventHandler(theLabel_MouseDown);
    }

    private void theLabel_MouseDown(object sender, MouseEventArgs e)
    {
        int xTrans = e.X + this.Location.X;
        int yTrans = e.Y + this.Location.Y;
        MouseEventArgs eTrans = new MouseEventArgs(e.Button, e.Clicks, xTrans, yTrans, e.Delta);
        this.OnMouseDown(eTrans);
    }
}

我无法将事件处理程序移动到控件的子类中,因为在父控件中引发事件的方法受到保护,并且我没有父控件的限定符:

无法通过System.Windows.Forms.Control 类型的限定符访问受保护成员System.Windows.Forms.Control.OnMouseDown(System.Windows.Forms.MouseEventArgs);限定符必须是TheProject.NoCaptureLabel 类型(或派生自它)。

我正在考虑在我的子类中覆盖控件的WndProc 方法,但希望有人能给我一个更简洁的解决方案。

【问题讨论】:

  • 这是此代码的正确错误消息吗?一个是 MouseUp,另一个是 MouseDown。
  • 我也有点不清楚您所说的“通过”是什么意思。
  • 报错信息不正确,应该是MouseDown。我所说的“通过”是指,当在控件上引发某些事件时,我会以编程方式在控件的父级上引发它们。

标签: c# winforms mouseevent


【解决方案1】:

您需要在基类中编写一个公共/受保护的方法,该方法将为您引发事件。然后从派生类调用这个方法。

这是你想要的吗?

public class MyLabel : Label
{
    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        //Do derived class stuff here
    }
}

【讨论】:

  • 我不这么认为。 OnMouseDown 引发事件,它不处理它。我需要一个将事件传递给它的父级的事件处理程序。而且我不能做你的第一个建议 b/c 基类是标准的 Windows 控件,而不是我编写的类。
  • @SandeepDatta,父控件和基类不同吧?
【解决方案2】:

WS_EX_TRANSPARENT 扩展窗口样式实际上就是这样做的(它是就地工具提示使用的)。您可能需要考虑应用这种样式,而不是编写大量的处理程序来为您完成。

为此,请覆盖CreateParams 方法:

protected override CreateParams CreateParams
{
  get
  {
    CreateParams cp=base.CreateParams;
    cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT
    return cp;
  }
}

进一步阅读:

【讨论】:

  • 感谢您的建议。我试过了,它在我的情况下不起作用。也许它只适用于顶级窗口?
【解决方案3】:

是的。经过一番搜索,我找到了文章"Floating Controls, tooltip-style",它使用WndProc将消息从WM_NCHITTEST更改为HTTRANSPARENT,使Control对鼠标事件透明。

为此,创建一个继承自Label 的控件并简单地添加以下代码。

protected override void WndProc(ref Message m)
{
    const int WM_NCHITTEST = 0x0084;
    const int HTTRANSPARENT = (-1);

    if (m.Msg == WM_NCHITTEST)
    {
        m.Result = (IntPtr)HTTRANSPARENT;
    }
    else
    {
        base.WndProc(ref m);
    }
}

我已经在 Visual Studio 2010 中使用 .NET Framework 4 客户端配置文件对此进行了测试。

【讨论】:

  • 谢谢 akatran -- 我已经继续前进了,我什至不记得我自己是如何解决这个问题的,但看起来你已经解决了。
  • 非常感谢,这对我也有帮助——清晰、简洁、解决问题!
  • 值得注意的是,这会将错误的透明控件从事件循环中移除——它们没有机会自己处理 MouseMove 事件,因为它直接钻取到父处理程序。要保留每个控件本身在将事件传递给父级之前处理事件的能力,您可以执行以下操作:stackoverflow.com/a/14814756/327083
  • 顺便说一句,将条件更改为(m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEHOVER) 允许鼠标悬停行为传递到下面的控件,在我的情况下也是如此。也许这对其他人也有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多