从列表中排除控件容器
本文关键字:控件 排除 列表 | 更新日期: 2023-09-27 18:16:44
如果我有一个带有这个容器的表单例如:
+---------------------------------panel 1----+
| |
| +------------------panel 2---+ |
| | | |
| | textbox1 | |
| | combobox1 checkBox1 | |
| +----------------------------+ |
| |
| +------------tableLayoutPanel1-+ |
| | | |
| | textbox2 | |
| +------------------------------+ |
| |
| +-------------FlowLayoutPanel1-+ |
| |textbox3 Combobox2 | |
| +------------------------------+ |
| |
+--------------------------------------------+
我已经有了一个函数,用于从给定的容器中获取特定类型的所有控件(通过递归调用来获取甚至包含的控件):
public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
IEnumerable<Control> controls = control.Controls.Cast<Control>();
return controls
.OfType<T>()
.Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)));
}
这很好(这里它返回textbox1, combobox1, checkbox1, textbox2, textbox3, combobox2)
现在,我想要一个具有类似行为的新函数:从容器中获取所有控件,但这些控件不包含在特定类型的容器中。在我的例子中,该函数可以返回panel1中包含的所有控件,这些控件从未包含在tableLayoutPanel中(这里是textbox1, combobox1, checkbox1, textbox3, combobox2)。
I've try:
public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
IEnumerable<Control> controls = control.Controls.Cast<Control>();
return controls
.OfType<T>()
.Concat<T>(controls .Where(ctrl => ctrl.GetType() != typeof(TableLayoutPanel))
.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl))
);
}
:
public static IEnumerable<T> FindAllChildrenByType2<T>(this Control control)
{
IEnumerable<Control> controls = control.Controls.Cast<Control>();
return controls
.OfType<T>()
.Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)))
.Where<T>(ctrl => ctrl.GetType() != typeof(TableLayoutPanel));
}
具有相同的结果:我得到了所有控件的列表,甚至是那些必须被排除的控件(在本例中tabelayoutpanel中的textBox2)。
你知道我在哪里迷路了吗?
基于这个使用非递归方法遍历树结构的漂亮答案,我想出了这个方法:
public static IEnumerable<TControl> GetChildControls<TControl>(this Control root,
Type excludedContainer = null)
where TControl : Control
{
var queue = new Queue<Control>();
queue.Enqueue(root);
while (queue.Any())
{
var next = queue.Dequeue();
if (!next.GetType().Equals(excludedContainer))
foreach (Control child in next.Controls)
{
queue.Enqueue(child);
}
if (!next.HasChildren && next is TControl typed)
{
yield return typed;
}
}
}
非递归方法总是首选,因为它们不会耗尽调用堆栈(尽管在本例中不太可能)。
它本质上和原来的一样:在while
循环中逐级收集控件。我只是用Queue
代替了Stack
,所以控制从上到下返回。当然,还添加了您要查找的条件:过滤类型和排除的容器类型。