teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

見直しキャンペーン中

2023/07/22 10:19

投稿

TN8001
TN8001

スコア10108

answer CHANGED
@@ -1,262 +1,262 @@
1
- YAmaGNZさん 2020/08/05 23:24 のコメントのざっくり実装です。
2
-
3
- 同様のものを作るのは大変なので、以下のように置き換えさせていただきます。
4
- ユーザーコントロール → Form1(Form)
5
- SplitContainerを拡張したコンポーネント → ParentPanel(FlowLayoutPanel)
6
- SplitterPanelを拡張したコンポーネント → ChildPanel(Panel)
7
-
8
- ChildPanelの追加・削除時にイベント登録・解除して、新しく作った専用のイベントにまわすだけです。
9
- 本題に関係ないコードのほうが多いですが、ポイントはコメントが入ってる部分だけです。
10
-
11
- ```C#
12
- using System;
13
- using System.Collections.Generic;
14
- using System.Diagnostics;
15
- using System.Drawing;
16
- using System.Linq;
17
- using System.Windows.Forms;
18
-
19
- namespace Questions282825
20
- {
21
- public partial class Form1 : Form
22
- {
23
- private ParentPanel parentPanel;
24
- private ListBox listBox;
25
-
26
- public Form1()
27
- {
28
- InitializeComponent();
29
-
30
- parentPanel = new ParentPanel() { Dock = DockStyle.Fill, };
31
-
32
- // 子供クリックイベントの登録
33
- parentPanel.ChildClick += ParentPanel_ChildClick;
34
- Controls.Add(parentPanel);
35
-
36
- var addButton = new Button { Dock = DockStyle.Bottom, Text = "add", };
37
- addButton.Click += AddButton_Click;
38
-
39
- var clearButton = new Button { Dock = DockStyle.Top, Text = "clear", };
40
- clearButton.Click += ClearButton_Click;
41
-
42
- var tableLayoutPanel = new TableLayoutPanel { Dock = DockStyle.Left, Width = 80, };
43
- tableLayoutPanel.Controls.Add(addButton, 0, 0);
44
- tableLayoutPanel.Controls.Add(clearButton, 0, 1);
45
- tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
46
- tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
47
- Controls.Add(tableLayoutPanel);
48
-
49
- listBox = new ListBox { Dock = DockStyle.Left, SelectionMode = SelectionMode.MultiSimple, };
50
- listBox.DataSource = new Color[] { Color.Red, Color.Green, Color.Blue, };
51
- Controls.Add(listBox);
52
- }
53
-
54
- private void ParentPanel_ChildClick(object sender, EventArgs e)
55
- {
56
- if(sender is Control control)
57
- {
58
- Debug.WriteLine($"{control.Name} {control.BackColor}");
59
- }
60
- }
61
-
62
- private void AddButton_Click(object sender, EventArgs e)
63
- {
64
- var colors = listBox.SelectedItems.Cast<Color>();
65
- parentPanel.AddRange(colors);
66
- }
67
-
68
- private void ClearButton_Click(object sender, EventArgs e)
69
- {
70
- parentPanel.Clear();
71
- }
72
-
73
-
74
- class ParentPanel : FlowLayoutPanel
75
- {
76
- // 新しく作った子供クリックイベント
77
- public event EventHandler ChildClick;
78
-
79
- public void AddRange(IEnumerable<Color> colors)
80
- {
81
- foreach(var color in colors)
82
- {
83
- var child = new ChildPanel(color);
84
-
85
- // 追加時にイベント登録
86
- child.Click += Child_Click;
87
- Controls.Add(child);
88
- }
89
- }
90
-
91
- public void Clear()
92
- {
93
- foreach(var child in Controls.Cast<Control>().ToArray())
94
- {
95
- // 削除時にイベント解除
96
- child.Click -= Child_Click;
97
- Controls.Remove(child);
98
- child.Dispose();
99
- }
100
- }
101
-
102
- private void Child_Click(object sender, EventArgs e)
103
- {
104
- // 子供クリックイベントを発砲(sender e そのまま渡しは雑い^^;
105
- ChildClick?.Invoke(sender, e);
106
- }
107
- }
108
-
109
- class ChildPanel : Panel
110
- {
111
- private static int i;
112
-
113
- public ChildPanel(Color color)
114
- {
115
- Name = $"Panel{++i}";
116
- Width = 100;
117
- Height = 100;
118
- BackColor = color;
119
- }
120
- }
121
- }
122
- }
123
- ```
124
-
125
- > そのたびにSplitterPanelに対してイベントを付与する必要
126
-
127
- もしかして「やれるのはわかっているが、いちいち登録解除がめんどくさい」って意味でしょうか?
128
-
129
- こんなソリューションがありました(この要件だとオーバーすぎる気がしますが)
130
- [Broadcasting Events through a Control Hierarchy - CodeProject](https://www.codeproject.com/Articles/13216/Broadcasting-Events-through-a-Control-Hierarchy)
131
- たしか無料登録しないとダウンロードできなかったと思うので、面倒な場合こちら(おそらく↑そのまま)
132
- [POSTSTAR/EventBroadcastProvider.cs at master · ohintaek/POSTSTAR](https://github.com/ohintaek/POSTSTAR/blob/master/PostStar.Basic/Common/EventBroadcastProvider.cs)
133
-
134
- 最初読み違えて`SplitContainer`を多段に入れ子すると思っていたので、そんな作りになってしまっています^^;
135
-
136
- ```C#
137
- using System;
138
- using System.Collections.Generic;
139
- using System.Diagnostics;
140
- using System.Drawing;
141
- using System.Linq;
142
- using System.Windows.Forms;
143
-
144
- namespace Questions282825
145
- {
146
- public partial class Form1 : Form
147
- {
148
- public Form1()
149
- {
150
- InitializeComponent();
151
-
152
- var splitContainer = new MySplitContainer();
153
- Controls.Add(splitContainer);
154
-
155
- // どちらにしろこれは必須
156
- var broadcastProvider = EventBroadcastProvider.CreateProvider(splitContainer, "Click");
157
-
158
- // 単にクリックが拾えればいい場合
159
- splitContainer.Click += SplitContainer_Click;
160
-
161
- // クリックされたコントロールやツリーも欲しい場合
162
- broadcastProvider.Relayed += BroadcastProvider_Relayed;
163
- }
164
-
165
- private void SplitContainer_Click(object sender, EventArgs e)
166
- {
167
- Debug.WriteLine("Click");
168
- }
169
-
170
- private void BroadcastProvider_Relayed(object sender, RelayedEventArgs e)
171
- {
172
- if(e.RelayChain[0] is Control control)
173
- {
174
- Debug.WriteLine($"{control.Name} {control.BackColor}");
175
- }
176
- }
177
-
178
-
179
- // 本題には関係ないが検証用に雑に作成
180
- class MySplitContainer : SplitContainer
181
- {
182
- private static List<KnownColor> colors;
183
- private static Random random = new Random();
184
- private static int i;
185
-
186
- private static ContextMenuStrip contextMenuStrip;
187
- private static ToolStripMenuItem addToolStripMenuItem;
188
- private static ToolStripMenuItem delToolStripMenuItem;
189
-
190
- static MySplitContainer()
191
- {
192
- colors = Enum.GetValues(typeof(KnownColor)).Cast<KnownColor>().ToList();
193
-
194
- addToolStripMenuItem = new ToolStripMenuItem { Text = "追加", };
195
- addToolStripMenuItem.Click += AddToolStripMenuItem_Click;
196
-
197
- delToolStripMenuItem = new ToolStripMenuItem { Text = "削除", };
198
- delToolStripMenuItem.Click += DelToolStripMenuItem_Click;
199
-
200
- contextMenuStrip = new ContextMenuStrip();
201
- contextMenuStrip.Items.Add(addToolStripMenuItem);
202
- contextMenuStrip.Items.Add(delToolStripMenuItem);
203
- }
204
-
205
- public MySplitContainer()
206
- {
207
- BorderStyle = BorderStyle.Fixed3D;
208
- Dock = DockStyle.Fill;
209
-
210
- Panel1.Name = $"Panel{++i}";
211
- Panel2.Name = $"Panel{++i}";
212
-
213
- Panel1.ContextMenuStrip = contextMenuStrip;
214
- Panel2.ContextMenuStrip = contextMenuStrip;
215
-
216
- Panel1.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
217
- Panel2.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
218
- }
219
-
220
- private static void AddToolStripMenuItem_Click(object sender, EventArgs e)
221
- {
222
- if(sender is ToolStripItem item)
223
- {
224
- if(item.Owner is ContextMenuStrip menuStrip)
225
- {
226
- if(menuStrip.SourceControl is SplitterPanel panel)
227
- {
228
- var o = (int)Orientation.Vertical;
229
- if(panel.Parent is SplitContainer container)
230
- {
231
- o = (int)container.Orientation;
232
- o ^= 1;
233
- }
234
-
235
- var sc = new MySplitContainer { Orientation = (Orientation)o };
236
- panel.Controls.Add(sc);
237
- }
238
- }
239
- }
240
- }
241
-
242
- private static void DelToolStripMenuItem_Click(object sender, EventArgs e)
243
- {
244
- if(sender is ToolStripItem item)
245
- {
246
- if(item.Owner is ContextMenuStrip menuStrip)
247
- {
248
- if(menuStrip.SourceControl is SplitterPanel panel)
249
- {
250
- if(panel.Parent is SplitContainer container)
251
- {
252
- container.Parent.Controls.Remove(container);
253
- container.Dispose();
254
- }
255
- }
256
- }
257
- }
258
- }
259
- }
260
- }
261
- }
1
+ YAmaGNZさん 2020/08/05 23:24 のコメントのざっくり実装です。
2
+
3
+ 同様のものを作るのは大変なので、以下のように置き換えさせていただきます。
4
+ ユーザーコントロール → Form1(Form)
5
+ SplitContainerを拡張したコンポーネント → ParentPanel(FlowLayoutPanel)
6
+ SplitterPanelを拡張したコンポーネント → ChildPanel(Panel)
7
+
8
+ ChildPanelの追加・削除時にイベント登録・解除して、新しく作った専用のイベントにまわすだけです。
9
+ 本題に関係ないコードのほうが多いですが、ポイントはコメントが入ってる部分だけです。
10
+
11
+ ```cs
12
+ using System;
13
+ using System.Collections.Generic;
14
+ using System.Diagnostics;
15
+ using System.Drawing;
16
+ using System.Linq;
17
+ using System.Windows.Forms;
18
+
19
+ namespace Questions282825
20
+ {
21
+ public partial class Form1 : Form
22
+ {
23
+ private ParentPanel parentPanel;
24
+ private ListBox listBox;
25
+
26
+ public Form1()
27
+ {
28
+ InitializeComponent();
29
+
30
+ parentPanel = new ParentPanel() { Dock = DockStyle.Fill, };
31
+
32
+ // 子供クリックイベントの登録
33
+ parentPanel.ChildClick += ParentPanel_ChildClick;
34
+ Controls.Add(parentPanel);
35
+
36
+ var addButton = new Button { Dock = DockStyle.Bottom, Text = "add", };
37
+ addButton.Click += AddButton_Click;
38
+
39
+ var clearButton = new Button { Dock = DockStyle.Top, Text = "clear", };
40
+ clearButton.Click += ClearButton_Click;
41
+
42
+ var tableLayoutPanel = new TableLayoutPanel { Dock = DockStyle.Left, Width = 80, };
43
+ tableLayoutPanel.Controls.Add(addButton, 0, 0);
44
+ tableLayoutPanel.Controls.Add(clearButton, 0, 1);
45
+ tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
46
+ tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
47
+ Controls.Add(tableLayoutPanel);
48
+
49
+ listBox = new ListBox { Dock = DockStyle.Left, SelectionMode = SelectionMode.MultiSimple, };
50
+ listBox.DataSource = new Color[] { Color.Red, Color.Green, Color.Blue, };
51
+ Controls.Add(listBox);
52
+ }
53
+
54
+ private void ParentPanel_ChildClick(object sender, EventArgs e)
55
+ {
56
+ if(sender is Control control)
57
+ {
58
+ Debug.WriteLine($"{control.Name} {control.BackColor}");
59
+ }
60
+ }
61
+
62
+ private void AddButton_Click(object sender, EventArgs e)
63
+ {
64
+ var colors = listBox.SelectedItems.Cast<Color>();
65
+ parentPanel.AddRange(colors);
66
+ }
67
+
68
+ private void ClearButton_Click(object sender, EventArgs e)
69
+ {
70
+ parentPanel.Clear();
71
+ }
72
+
73
+
74
+ class ParentPanel : FlowLayoutPanel
75
+ {
76
+ // 新しく作った子供クリックイベント
77
+ public event EventHandler ChildClick;
78
+
79
+ public void AddRange(IEnumerable<Color> colors)
80
+ {
81
+ foreach(var color in colors)
82
+ {
83
+ var child = new ChildPanel(color);
84
+
85
+ // 追加時にイベント登録
86
+ child.Click += Child_Click;
87
+ Controls.Add(child);
88
+ }
89
+ }
90
+
91
+ public void Clear()
92
+ {
93
+ foreach(var child in Controls.Cast<Control>().ToArray())
94
+ {
95
+ // 削除時にイベント解除
96
+ child.Click -= Child_Click;
97
+ Controls.Remove(child);
98
+ child.Dispose();
99
+ }
100
+ }
101
+
102
+ private void Child_Click(object sender, EventArgs e)
103
+ {
104
+ // 子供クリックイベントを発砲(sender e そのまま渡しは雑い^^;
105
+ ChildClick?.Invoke(sender, e);
106
+ }
107
+ }
108
+
109
+ class ChildPanel : Panel
110
+ {
111
+ private static int i;
112
+
113
+ public ChildPanel(Color color)
114
+ {
115
+ Name = $"Panel{++i}";
116
+ Width = 100;
117
+ Height = 100;
118
+ BackColor = color;
119
+ }
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ > そのたびにSplitterPanelに対してイベントを付与する必要
126
+
127
+ もしかして「やれるのはわかっているが、いちいち登録解除がめんどくさい」って意味でしょうか?
128
+
129
+ こんなソリューションがありました(この要件だとオーバーすぎる気がしますが)
130
+ [Broadcasting Events through a Control Hierarchy - CodeProject](https://www.codeproject.com/Articles/13216/Broadcasting-Events-through-a-Control-Hierarchy)
131
+ たしか無料登録しないとダウンロードできなかったと思うので、面倒な場合こちら(おそらく↑そのまま)
132
+ [POSTSTAR/EventBroadcastProvider.cs at master · ohintaek/POSTSTAR](https://github.com/ohintaek/POSTSTAR/blob/master/PostStar.Basic/Common/EventBroadcastProvider.cs)
133
+
134
+ 最初読み違えて`SplitContainer`を多段に入れ子すると思っていたので、そんな作りになってしまっています^^;
135
+
136
+ ```cs
137
+ using System;
138
+ using System.Collections.Generic;
139
+ using System.Diagnostics;
140
+ using System.Drawing;
141
+ using System.Linq;
142
+ using System.Windows.Forms;
143
+
144
+ namespace Questions282825
145
+ {
146
+ public partial class Form1 : Form
147
+ {
148
+ public Form1()
149
+ {
150
+ InitializeComponent();
151
+
152
+ var splitContainer = new MySplitContainer();
153
+ Controls.Add(splitContainer);
154
+
155
+ // どちらにしろこれは必須
156
+ var broadcastProvider = EventBroadcastProvider.CreateProvider(splitContainer, "Click");
157
+
158
+ // 単にクリックが拾えればいい場合
159
+ splitContainer.Click += SplitContainer_Click;
160
+
161
+ // クリックされたコントロールやツリーも欲しい場合
162
+ broadcastProvider.Relayed += BroadcastProvider_Relayed;
163
+ }
164
+
165
+ private void SplitContainer_Click(object sender, EventArgs e)
166
+ {
167
+ Debug.WriteLine("Click");
168
+ }
169
+
170
+ private void BroadcastProvider_Relayed(object sender, RelayedEventArgs e)
171
+ {
172
+ if(e.RelayChain[0] is Control control)
173
+ {
174
+ Debug.WriteLine($"{control.Name} {control.BackColor}");
175
+ }
176
+ }
177
+
178
+
179
+ // 本題には関係ないが検証用に雑に作成
180
+ class MySplitContainer : SplitContainer
181
+ {
182
+ private static List<KnownColor> colors;
183
+ private static Random random = new Random();
184
+ private static int i;
185
+
186
+ private static ContextMenuStrip contextMenuStrip;
187
+ private static ToolStripMenuItem addToolStripMenuItem;
188
+ private static ToolStripMenuItem delToolStripMenuItem;
189
+
190
+ static MySplitContainer()
191
+ {
192
+ colors = Enum.GetValues(typeof(KnownColor)).Cast<KnownColor>().ToList();
193
+
194
+ addToolStripMenuItem = new ToolStripMenuItem { Text = "追加", };
195
+ addToolStripMenuItem.Click += AddToolStripMenuItem_Click;
196
+
197
+ delToolStripMenuItem = new ToolStripMenuItem { Text = "削除", };
198
+ delToolStripMenuItem.Click += DelToolStripMenuItem_Click;
199
+
200
+ contextMenuStrip = new ContextMenuStrip();
201
+ contextMenuStrip.Items.Add(addToolStripMenuItem);
202
+ contextMenuStrip.Items.Add(delToolStripMenuItem);
203
+ }
204
+
205
+ public MySplitContainer()
206
+ {
207
+ BorderStyle = BorderStyle.Fixed3D;
208
+ Dock = DockStyle.Fill;
209
+
210
+ Panel1.Name = $"Panel{++i}";
211
+ Panel2.Name = $"Panel{++i}";
212
+
213
+ Panel1.ContextMenuStrip = contextMenuStrip;
214
+ Panel2.ContextMenuStrip = contextMenuStrip;
215
+
216
+ Panel1.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
217
+ Panel2.BackColor = Color.FromKnownColor(colors.Skip(random.Next(0, colors.Count)).First());
218
+ }
219
+
220
+ private static void AddToolStripMenuItem_Click(object sender, EventArgs e)
221
+ {
222
+ if(sender is ToolStripItem item)
223
+ {
224
+ if(item.Owner is ContextMenuStrip menuStrip)
225
+ {
226
+ if(menuStrip.SourceControl is SplitterPanel panel)
227
+ {
228
+ var o = (int)Orientation.Vertical;
229
+ if(panel.Parent is SplitContainer container)
230
+ {
231
+ o = (int)container.Orientation;
232
+ o ^= 1;
233
+ }
234
+
235
+ var sc = new MySplitContainer { Orientation = (Orientation)o };
236
+ panel.Controls.Add(sc);
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ private static void DelToolStripMenuItem_Click(object sender, EventArgs e)
243
+ {
244
+ if(sender is ToolStripItem item)
245
+ {
246
+ if(item.Owner is ContextMenuStrip menuStrip)
247
+ {
248
+ if(menuStrip.SourceControl is SplitterPanel panel)
249
+ {
250
+ if(panel.Parent is SplitContainer container)
251
+ {
252
+ container.Parent.Controls.Remove(container);
253
+ container.Dispose();
254
+ }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+ }
261
+ }
262
262
  ```