YAmaGNZさん 2020/08/05 23:24 のコメントのざっくり実装です。
同様のものを作るのは大変なので、以下のように置き換えさせていただきます。
ユーザーコントロール → Form1(Form)
SplitContainerを拡張したコンポーネント → ParentPanel(FlowLayoutPanel)
SplitterPanelを拡張したコンポーネント → ChildPanel(Panel)
ChildPanelの追加・削除時にイベント登録・解除して、新しく作った専用のイベントにまわすだけです。
本題に関係ないコードのほうが多いですが、ポイントはコメントが入ってる部分だけです。
cs
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Drawing;
5using System.Linq;
6using System.Windows.Forms;
7
8namespace Questions282825
9{
10 public partial class Form1 : Form
11 {
12 private ParentPanel parentPanel;
13 private ListBox listBox;
14
15 public Form1()
16 {
17 InitializeComponent();
18
19 parentPanel = new ParentPanel() { Dock = DockStyle.Fill, };
20
21 // 子供クリックイベントの登録
22 parentPanel.ChildClick += ParentPanel_ChildClick;
23 Controls.Add(parentPanel);
24
25 var addButton = new Button { Dock = DockStyle.Bottom, Text = "add", };
26 addButton.Click += AddButton_Click;
27
28 var clearButton = new Button { Dock = DockStyle.Top, Text = "clear", };
29 clearButton.Click += ClearButton_Click;
30
31 var tableLayoutPanel = new TableLayoutPanel { Dock = DockStyle.Left, Width = 80, };
32 tableLayoutPanel.Controls.Add(addButton, 0, 0);
33 tableLayoutPanel.Controls.Add(clearButton, 0, 1);
34 tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
35 tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
36 Controls.Add(tableLayoutPanel);
37
38 listBox = new ListBox { Dock = DockStyle.Left, SelectionMode = SelectionMode.MultiSimple, };
39 listBox.DataSource = new Color[] { Color.Red, Color.Green, Color.Blue, };
40 Controls.Add(listBox);
41 }
42
43 private void ParentPanel_ChildClick(object sender, EventArgs e)
44 {
45 if(sender is Control control)
46 {
47 Debug.WriteLine($"{control.Name} {control.BackColor}");
48 }
49 }
50
51 private void AddButton_Click(object sender, EventArgs e)
52 {
53 var colors = listBox.SelectedItems.Cast<Color>();
54 parentPanel.AddRange(colors);
55 }
56
57 private void ClearButton_Click(object sender, EventArgs e)
58 {
59 parentPanel.Clear();
60 }
61
62
63 class ParentPanel : FlowLayoutPanel
64 {
65 // 新しく作った子供クリックイベント
66 public event EventHandler ChildClick;
67
68 public void AddRange(IEnumerable<Color> colors)
69 {
70 foreach(var color in colors)
71 {
72 var child = new ChildPanel(color);
73
74 // 追加時にイベント登録
75 child.Click += Child_Click;
76 Controls.Add(child);
77 }
78 }
79
80 public void Clear()
81 {
82 foreach(var child in Controls.Cast<Control>().ToArray())
83 {
84 // 削除時にイベント解除
85 child.Click -= Child_Click;
86 Controls.Remove(child);
87 child.Dispose();
88 }
89 }
90
91 private void Child_Click(object sender, EventArgs e)
92 {
93 // 子供クリックイベントを発砲(sender e そのまま渡しは雑い^^;
94 ChildClick?.Invoke(sender, e);
95 }
96 }
97
98 class ChildPanel : Panel
99 {
100 private static int i;
101
102 public ChildPanel(Color color)
103 {
104 Name = $"Panel{++i}";
105 Width = 100;
106 Height = 100;
107 BackColor = color;
108 }
109 }
110 }
111}
そのたびにSplitterPanelに対してイベントを付与する必要
もしかして「やれるのはわかっているが、いちいち登録解除がめんどくさい」って意味でしょうか?
こんなソリューションがありました(この要件だとオーバーすぎる気がしますが)
Broadcasting Events through a Control Hierarchy - CodeProject
たしか無料登録しないとダウンロードできなかったと思うので、面倒な場合こちら(おそらく↑そのまま)
POSTSTAR/EventBroadcastProvider.cs at master · ohintaek/POSTSTAR
最初読み違えてSplitContainer
を多段に入れ子すると思っていたので、そんな作りになってしまっています^^;
cs
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.Drawing;
5using System.Linq;
6using System.Windows.Forms;
7
8namespace Questions282825
9{
10 public partial class Form1 : Form
11 {
12 public Form1()
13 {
14 InitializeComponent();
15
16 var splitContainer = new MySplitContainer();
17 Controls.Add(splitContainer);
18
19 // どちらにしろこれは必須
20 var broadcastProvider = EventBroadcastProvider.CreateProvider(splitContainer, "Click");
21
22 // 単にクリックが拾えればいい場合
23 splitContainer.Click += SplitContainer_Click;
24
25 // クリックされたコントロールやツリーも欲しい場合
26 broadcastProvider.Relayed += BroadcastProvider_Relayed;
27 }
28
29 private void SplitContainer_Click(object sender, EventArgs e)
30 {
31 Debug.WriteLine("Click");
32 }
33
34 private void BroadcastProvider_Relayed(object sender, RelayedEventArgs e)
35 {
36 if(e.RelayChain[0] is Control control)
37 {
38 Debug.WriteLine($"{control.Name} {control.BackColor}");
39 }
40 }
41
42
43 // 本題には関係ないが検証用に雑に作成
44 class MySplitContainer : SplitContainer
45 {
46 private static List<KnownColor> colors;
47 private static Random random = new Random();
48 private static int i;
49
50 private static ContextMenuStrip contextMenuStrip;
51 private static ToolStripMenuItem addToolStripMenuItem;
52 private static ToolStripMenuItem delToolStripMenuItem;
53
54 static MySplitContainer()
55 {
56 colors = Enum.GetValues(typeof(KnownColor)).Cast<KnownColor>().ToList();
57
58 addToolStripMenuItem = new ToolStripMenuItem { Text = "追加", };
59 addToolStripMenuItem.Click += AddToolStripMenuItem_Click;
60
61 delToolStripMenuItem = new ToolStripMenuItem { Text = "削除", };
62 delToolStripMenuItem.Click += DelToolStripMenuItem_Click;
63
64 contextMenuStrip = new ContextMenuStrip();
65 contextMenuStrip.Items.Add(addToolStripMenuItem);
66 contextMenuStrip.Items.Add(delToolStripMenuItem);
67 }
68
69 public MySplitContainer()
70 {
71 BorderStyle = BorderStyle.Fixed3D;
72 Dock = DockStyle.Fill;
73
74 Panel1.Name = $"Panel{++i}";
75 Panel2.Name = $"Panel{++i}";
76
77 Panel1.ContextMenuStrip = contextMenuStrip;
78 Panel2.ContextMenuStrip = contextMenuStrip;
79
80 Panel1.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
81 Panel2.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
82 }
83
84 private static void AddToolStripMenuItem_Click(object sender, EventArgs e)
85 {
86 if(sender is ToolStripItem item)
87 {
88 if(item.Owner is ContextMenuStrip menuStrip)
89 {
90 if(menuStrip.SourceControl is SplitterPanel panel)
91 {
92 var o = (int)Orientation.Vertical;
93 if(panel.Parent is SplitContainer container)
94 {
95 o = (int)container.Orientation;
96 o ^= 1;
97 }
98
99 var sc = new MySplitContainer { Orientation = (Orientation)o };
100 panel.Controls.Add(sc);
101 }
102 }
103 }
104 }
105
106 private static void DelToolStripMenuItem_Click(object sender, EventArgs e)
107 {
108 if(sender is ToolStripItem item)
109 {
110 if(item.Owner is ContextMenuStrip menuStrip)
111 {
112 if(menuStrip.SourceControl is SplitterPanel panel)
113 {
114 if(panel.Parent is SplitContainer container)
115 {
116 container.Parent.Controls.Remove(container);
117 container.Dispose();
118 }
119 }
120 }
121 }
122 }
123 }
124 }
125}