As such, the routing of events between the parent and child controls in WinForms is not provided, it is only in WPF. But you can partially simulate the routing of events from the child to the parent and use the following simple technique:
public partial class MyTableLayoutPanel:TableLayoutPanel { public MyTableLayoutPanel() { InitializeComponent(); // ΠΠΎΠ΄ΠΏΠΈΡΡΠ²Π°Π΅ΠΌΡΡ Π½Π° ΡΠΎΠ±ΡΡΠΈΠ΅ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ Π΄ΠΎΡΠ΅ΡΠ½Π΅Π³ΠΎ ΠΊΠΎΠ½ΡΡΠΎΠ»Π° this.ControlAdded += MyTableLayoutPanel_ControlAdded; // ΠΠΎΠ΄ΠΏΠΈΡΡΠ²Π°Π΅ΠΌΡΡ Π½Π° ΡΠΎΠ±ΡΡΠΈΠ΅ ΡΠ΄Π°Π»Π΅Π½ΠΈΡ Π΄ΠΎΡΠ΅ΡΠ½Π΅Π³ΠΎ ΠΊΠΎΠ½ΡΡΠΎΠ»Π° this.ControlRemoved += MyTableLayoutPanel_ControlRemoved; }
The Control.ControlAdded and Control.ControlRemoved events are triggered when child controls are added to the control. We will use this in order not to subscribe by hand to the events of the child controls to perform actions on the container.
void MyTableLayoutPanel_ControlAdded(object sender, ControlEventArgs e) { // ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ ΡΠ²ΠΎΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΊ Π½ΡΠΆΠ½ΡΠΌ ΡΠΎΠ±ΡΡΠΈΡΠΌ Π΄ΠΎΡΠ΅ΡΠ½Π΅Π³ΠΎ ΠΊΠΎΠ½ΡΡΠΎΠ»Π° // ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅ΡΡΡ Π² ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ e.Control.MouseUp += MouseUpHandler; e.Control.MouseDown += MouseDownHandler; e.Control.MouseMove += MouseMoveHandler; } void MyTableLayoutPanel_ControlRemoved(object sender, ControlEventArgs e) { // ΠΠ΅ Π·Π°Π±ΡΠ²Π°Π΅ΠΌ ΠΎΡΠΏΠΈΡΠ°ΡΡ Π΄ΠΎΡΠ΅ΡΠ½ΠΈΠΉ ΠΊΠΎΠ½ΡΡΠΎΠ» ΠΎΡ Π½Π°ΡΠΈΡ
ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ² ΠΏΡΠΈ Π΅Π³ΠΎ ΡΠ΄Π°Π»Π΅Π½ΠΈΠΈ, // ΡΡΠΎΠ±Ρ Π½Π΅ ΡΠ΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ ΡΡΡΠ»ΠΊΡ Π½Π° ΠΎΠ±ΡΠ΅ΠΊΡ Π΄ΠΎΠ»ΡΡΠ΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ e.Control.MouseUp -= MouseUpHandler; e.Control.MouseDown -= MouseDownHandler; e.Control.MouseMove -= MouseMoveHandler; }
Events are based on delegates, and the delegate keeps a reference to the object whose method has been passed to it, so in order not to get a memory leak, do not forget to unsubscribe from the events when removing the control from the parent container. Also, in the handler of the ContolAdded event, you can make additional settings for the properties of the child controls.
And finally, we describe the handlers of the events we need to manage the parent container.
private void MouseUpHandler(object sender, MouseEventArgs e) { MouseEventArgs newArgs = new MouseEventArgs( e.Button, e.Clicks, ((Control)sender).Location.X+eX, ((Control)sender).Location.Y+eY, e.Delta); OnMouseUp(newArgs); } // ΠΈ ΡΠ°ΠΊ Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΡΠΎΠ±ΡΡΠΈΡ, ΠΊΠΎΡΠΎΡΠΎΠ΅ Π½ΡΠΆΠ½ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Π² ΡΠΎΠ΄ΠΈΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΊΠΎΠ½ΡΠ΅ΠΉΠ½Π΅Ρ }
If everything is done correctly, your child controls will also call the handlers of the parent container. One more nuance, the handler of the parent container must carefully check who caused it and transfer the coordinates from the coordinate system of the child control to its own, if of course it receives the coordinates in the event arguments and uses them. It may also concern other event arguments, so be careful when developing the logic of such forced event handlers.
Also read this question and answers , there is proposed a solution that may be suitable for your purposes.
Another solution is to switch to WPF and use event routing, which is available there without out-of-the-box shamanism.