将子控件的MouseMove事件无缝转发给父控件

3
我有一个自定义的UserControl,使用GDI+进行绘制。它是一个透明控件,在父控件上方绘制小形状。
父窗口所做的一切就是创建控件,给它一个矩形来绘制自己,然后如果用户单击非透明区域,它就会接收事件。
绘图部分完美地运作,但现在我需要尽可能无缝地将所有MouseMove、MouseClick等事件转发到父控件,前提是这些事件发生在形状之外。
形状是使用GraphicsPath绘制的,我已经能够通过GraphicsPath.IsVisible()检测鼠标位置是否在形状上方。
我希望以零或最少的额外代码在父控件上实现这一点。父控件不应该知道MouseMove事件是从子控件转发过来的还是其他事件,它们应该平等对待。
我需要使用pinvoke/SendMessage()来完成这个任务吗?还是有更简单的方法使用.NET框架?
1个回答

7

这在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
        }
    }
}

以以下格式测试代码:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接