4

I have a user control consisting of many children controls, and I need to handle the user control's double-click event. So I add the event handler but it's never triggered.

The quickest solution I am finding is to iterate through the children controls and subscribe to their double-click events. Is this really the right way to do it? Are there better ways? Thank you.

Ola Ström
  • 4,136
  • 5
  • 22
  • 41
  • 1
    You could create a Singelton as a kind of managing class and that "route" you event to your first Control or handel it, Keyword: Observer pattern and Singelton. Thats what i would do – Venson Jan 18 '13 at 15:26
  • 1
    This could also interesting for your case: [http://stackoverflow.com/a/587123/674700](http://stackoverflow.com/a/587123/674700) – Alex Filipovici Jan 18 '13 at 15:26
  • 1
    I believe that controls that stand on your way are labels, and then you should draw them instead of adding labels, not just because of your problem, but also because of the effect on system resources. – Ivan Ičin Jan 18 '13 at 17:21

2 Answers2

6

The following will work only for the first level children control which are being added to the user control. It will not work for the controls which are added subsequently to these children. For example, it will work for a double-click on a first level Panel child control, but not on a Label which is added to the panel.

Test.cs

public partial class Test : UserControl
{
    public Test()
    {
        InitializeComponent();
    }

    protected override void OnControlAdded(ControlEventArgs e)
    {
        e.Control.DoubleClick += Control_DoubleClick;
        base.OnControlAdded(e);
    }

    void Control_DoubleClick(object sender, EventArgs e)
    {
        MessageBox.Show("User control clicked");
        OnDoubleClick(e);
    }
}

Form1.cs

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        var test = new Test();
        var label = new Label();
        label.Text = "test";
        test.Controls.Add(label);
        Controls.Add(test);
    }
}

To address the other case, when you have controls contained inside controls, you can use the following code. Be sure to add the user control to it's parent control before adding any other child controls to it. Once you do that, follow the same principle as you go down the control hierarchy.

To put it simpler, before adding a control anywhere in the control hierarchy, make sure that it's parent is already added to a control collection.

Test.cs

protected override void OnControlAdded(ControlEventArgs e)
{
    e.Control.DoubleClick += Control_DoubleClick;
    e.Control.ControlAdded += OnControlAdded; // add this line
    base.OnControlAdded(e);
}

// add this method
private void OnControlAdded(object sender, ControlEventArgs e)
{
    e.Control.DoubleClick += Control_DoubleClick;
    e.Control.ControlAdded += OnControlAdded;
}

Form1.cs

private void Form1_Load(object sender, EventArgs e)
{
    var test = new Test();
    var panel1 = new Panel();
    panel1.BackColor = Color.AliceBlue;
    var panel2 = new Panel();
    panel2.BackColor = Color.AntiqueWhite;

    var label1 = new Label();
    label1.Text = "test 1";
    label1.BackColor = Color.Aquamarine;

    var label2 = new Label();
    label2.Text = "test 2";
    label2.BackColor = Color.Azure;

    // !!! order is important !!!
    // first add at least one child control to the test control

    // this works as expected
    //Controls.Add(test);
    //test.Controls.Add(panel1);
    //panel1.Controls.Add(panel2);
    //panel2.Left = 50;
    //panel1.Controls.Add(label1);
    //panel2.Controls.Add(label2);

    // this works as expected
    //test.Controls.Add(panel1);
    //Controls.Add(test);
    //panel1.Controls.Add(panel2);
    //panel2.Left = 50;
    //panel1.Controls.Add(label1);
    //panel2.Controls.Add(label2);

    // this doesn't work for panel2 and it's children
    Controls.Add(test);
    panel1.Controls.Add(panel2); // panel2 & children will not trigger the events

    // all controls added to control collections 
    // prior to this line will not trigger the event
    test.Controls.Add(panel1); 

    panel2.Left = 50;
    panel1.Controls.Add(label1);
    panel2.Controls.Add(label2); // will not trigger the event
}
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
1

To create a nice UI it's helpful to use a (panel) parent control and many children controls (within). E.g. one panel (parent) with many labels (Children).

I use this code when I want to add MouseEnter events (and any other events) to a specific parent control and all its children controls.

It's perfect when you build your own button from panels and labels and what to handle it as one single control to handle MouseOver or something else.

I also added some code that adds MouseEnter events (and any other events) to all other controls and its children controls. Hope it can help someone...

// ------------ WINDOWS FORM'S CLASS ------------------------------------
public partial class WFEvent : Form
{

    // ------------ CONSTRUCTOR -----------------------------------------
    public WFEvent()
    {
        // Create Events for Control
        CreateEventsControl(pnlParent);

        // Create Events for Other Controls
        CreateEventsOtherControls(this);
    }

    // ------------ PRIVATE METHODS -------------------------------------
    // Create Events for Parent Control (e.g. a Panel) and Child Controls...
    private void CreateEventsControl(Control control)
    {
        // Create Events for Parent Control
        control.MouseEnter += (sender, e) => { CtlMouseEnter(control); };
        control.Click += (sender, e) => { CtlClick(control); };

        // Create Events for Child Controls...
        CreateEventsControlChildControls(control);
    }

    // Create Events for Parent Control's Child Controls...
    private void CreateEventsControlChildControls(Control control)
    {
        foreach (Control childControl in control.Controls)
        {
            // Create Events for Parent Panel's Child Control
            childControl.MouseEnter += (sender, e) => { CtlMouseEnter(control); };
            childControl.Click += (sender, e) => { CtlClick(control); };

            // Create Events for Child Control's Child Controls...
            CreateEventsControlChildControls(childControl);
        }
    }

    // Create Events for Other Control's Parent and Child Controls...
    private void CreateEventsOtherControls(Control control)
    {
        // Create Event for Other Control's Parent Control
        control.MouseEnter += (sender, e) => { CtlOtherMouseEnter(control); };
        //control.Click += (sender, e) => { CtlOtherClick(control); };

        // Create Event for Other Control's Child Control...
        CreateEventsOtherControlsChildControls(control);
    }

    // Create Event for Other Control's Child Controls...
    private void CreateEventsOtherControlsChildControls(Control control)
    {
        foreach (Control childControl in control.Controls)
        {
            if (childControl != pnlParent)
            {
                // Create Events for Other Control's Child Control
                childControl.MouseEnter += (sender, e) => { CtlOtherMouseEnter(control); };
            //childControl.Click += (sender, e) => { CtlOtherClick(control); };

                // Create Events for Other Control's Child Controls's Child Control...
                CreateEventsOtherControlsChildControls(childControl);
            }
        }
    }

    // MouseEnter for Controls
    private void CtlMouseEnter(Control control) 
    {
            Code...
    }

    // Click for Controls
    private void CtlClick(Control control) 
    {
            Code...
    }

    // MouseEnter for Other Controls
    private void CtlOtherMouseEnter(Control control) 
    {
            Code...
    }

    // Click for Other Controls
    //private void CtlOtherClick(Control control) 
    //{
    //        Code...
    //}
}
Ola Ström
  • 4,136
  • 5
  • 22
  • 41