Handling a Click for all controls on a Form

2019-01-03 17:53发布

I have a .NET UserControl (FFX 3.5). This control contains several child Controls - a Panel, a couple Labels, a couple TextBoxes, and yet another custom Control. I want to handle a right click anywhere on the base Control - so a right click on any child control (or child of a child in the case of the Panel). I'd like to do it so that it's maintainable if someone makes changes to the Control without having to wire in handlers for new Controls for example.

First I tried overriding the WndProc, but as I suspected, I only get messages for clicks on the Form directly, not any of its children. As a semi-hack, I added the following after InitializeComponent:

  foreach (Control c in this.Controls)
  {
    c.MouseClick += new MouseEventHandler(
      delegate(object sender, MouseEventArgs e)
      {
        // handle the click here
      });
  }

This now gets clicks for controls that support the event, but Labels, for example, still don't get anything. Is there a simple way to do this that I'm overlooking?

2条回答
闹够了就滚
2楼-- · 2019-01-03 18:25

To handle a MouseClick event for right click on all the controls on a custom UserControl:

public class MyClass : UserControl
{
    public MyClass()
    {
        InitializeComponent();

        MouseClick += ControlOnMouseClick;
        if (HasChildren)
            AddOnMouseClickHandlerRecursive(Controls);
    }

    private void AddOnMouseClickHandlerRecursive(IEnumerable controls)
    {
        foreach (Control control in controls)
        {
            control.MouseClick += ControlOnMouseClick;

            if (control.HasChildren)
                AddOnMouseClickHandlerRecursive(control.Controls);
        }
    }

    private void ControlOnMouseClick(object sender, MouseEventArgs args)
    {
        if (args.Button != MouseButtons.Right)
            return;

        var contextMenu = new ContextMenu(new[] { new MenuItem("Copy", OnCopyClick) });
        contextMenu.Show((Control)sender, new Point(args.X, args.Y));
    }

    private void OnCopyClick(object sender, EventArgs eventArgs)
    {
        MessageBox.Show("Copy menu item was clicked.");
    }
}
查看更多
我命由我不由天
3楼-- · 2019-01-03 18:39

If the labels are in a subcontrol then you'd have to do this recursively:

void initControlsRecursive(ControlCollection coll)
 { 
    foreach (Control c in coll)  
     {  
       c.MouseClick += (sender, e) => {/* handle the click here  */});  
       initControlsRecursive(c.Controls);
     }
 }

/* ... */
initControlsRecursive(Form.Controls);
查看更多
登录 后发表回答