将子控制MouseMove事件无缝转发到父级

Tre*_*ott 2 c# parent mousemove winforms

我有一个使用GDI +绘制的自定义UserControl.它是一个透明控件,在父控件的顶部绘制小形状.

所有父窗口都创建控件,为其绘制一个Rectangle以在其中绘制自身,然后在用户单击非透明区域时接收事件.

绘图部分工作正常,但现在我需要做的是尽可能无缝地将所有MouseMove,MouseClick等事件转发到父控件,如果这些事件发生在形状之外.

使用GraphicsPath绘制形状,我已经能够使用GraphicsPath.IsVisible()检测鼠标位置是否在形状上.

我希望以一种在父级上需要零或最少额外代码的方式执行此操作.父母不一定知道MouseMove事件是否是从子控件转发的,它应该平等对待它们.

我必须使用pinvoke/SendMessage()来执行此操作吗?或者使用.NET框架有更简单的方法吗?

Han*_*ant 6

这在winapi中是可能的,窗口管理器发送WM_NCHITTEST消息,询问鼠标位于控件的哪个部分.你可以做的是返回HTTRANSPARENT,它将询问父窗口.这是一个实现此功能的UserControl示例.捕获消息需要覆盖WndProc():

public partial class UserControl1 : UserControl {
    public UserControl1() {
        InitializeComponent();
        paths = new List<GraphicsPath>();
        GraphicsPath example = new GraphicsPath();
        example.AddEllipse(new Rectangle(10, 10, 50, 30));
        paths.Add(example);
    }
    List<GraphicsPath> paths;

    protected override void OnPaint(PaintEventArgs e) {
        foreach (var path in paths) e.Graphics.FillPath(Brushes.Blue, path);
        base.OnPaint(e);
    }

    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        // Trap WM_NCHITTEST on the client area
        if (m.Msg == 0x84 && m.Result == (IntPtr)1) {
            Point pos = new Point(m.LParam.ToInt32());
            pos = this.PointToClient(pos);
            bool oncurve = false;
            foreach (var path in paths)
                if (path.IsVisible(pos)) oncurve = true;
            if (!oncurve) m.Result = (IntPtr)(-1);  // HTTRANSPARENT
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

表格中的测试代码:

    private void userControl11_MouseMove(object sender, MouseEventArgs e) {
        Console.WriteLine("On shape {0}", e.Location);
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e) {
        Console.WriteLine("On form  {0}", e.Location);
    }
Run Code Online (Sandbox Code Playgroud)