2011-10-07 76 views
2

我使用GDI +绘制了自定义UserControl。这是一个透明的控件,它在父控件的顶部绘制小形状。将子控件MouseMove事件无缝地转发给父项

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

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

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

我想以这样的方式做到这一点,在父母上需要零或最小的额外代码。父母不一定知道MouseMove事件是否从子控件转发,它应该平等对待它们。

我必须pinvoke/SendMessage()来做到这一点吗?还是有更简单的方法使用.NET框架?

回答

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

测试代码形式:

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