C# 从列表中排除控件容器
例如,如果我有一个带有此容器的表单:C# 从列表中排除控件容器,c#,linq,predicate,C#,Linq,Predicate,例如,如果我有一个带有此容器的表单: +---------------------------------panel 1----+ | | | +------------------panel 2---+ | | | | | | | textbox1 |
+---------------------------------panel 1----+
| |
| +------------------panel 2---+ |
| | | |
| | textbox1 | |
| | combobox1 checkBox1 | |
| +----------------------------+ |
| |
| +------------tableLayoutPanel1-+ |
| | | |
| | textbox2 | |
| +------------------------------+ |
| |
| +-------------FlowLayoutPanel1-+ |
| |textbox3 Combobox2 | |
| +------------------------------+ |
| |
+--------------------------------------------+
我已经有了一个函数,用于从给定容器中获取特定类型的所有控件(通过递归调用获取包含的偶数控件):
公共静态IEnumerable FindAllChildrenByType(此控件)
{
IEnumerable controls=control.controls.Cast();
返回控件
第()类
.Concat(controls.SelectMany(ctrl=>FindAllChildrenByType(ctrl));
}
这可以正常工作(这里返回textbox1、combobox1、checkbox1、textbox2、textbox3、combobox2)
现在,我想要一个具有类似行为的新函数:从容器中获取所有控件,但这些控件不包括在特定类型的容器中。
在我的示例中,该函数可以返回panel1中包含的所有控件,这些控件从未包含在tableLayoutPanel中(此处为textbox1、combobox1、checkbox1、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 .Where(ctrl => ctrl.GetType() != typeof(TableLayoutPanel))
.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl))
);
}
公共静态IEnumerable FindAllChildrenByType(此控件)
{
IEnumerable controls=control.controls.Cast();
返回控件
第()类
.Concat(controls.Where(ctrl=>ctrl.GetType()!=typeof(TableLayoutPanel))
.SelectMany(ctrl=>FindAllChildrenByType(ctrl))
);
}
以及:
公共静态IEnumerable FindAllChildrenByType2(此控件)
{
IEnumerable controls=control.controls.Cast();
返回控件
第()类
.Concat(controls.SelectMany(ctrl=>FindAllChildrenByType(ctrl)))
.Where(ctrl=>ctrl.GetType()!=typeof(TableLayoutPanel));
}
同样的结果是:我得到了所有控件的列表,甚至那些必须被排除的控件(示例中TableLayoutPanel中的textBox2)
知道我在哪里迷路了吗?基于使用非递归方法遍历树结构,我想出了这个方法:
公共静态IEnumerable GetChildControls(此控件根,
类型excludedContainer=null)
其中TControl:Control
{
var queue=新队列();
queue.Enqueue(root);
while(queue.Any())
{
var next=queue.Dequeue();
如果(!next.GetType().Equals(excludedContainer))
foreach(next.Controls中的控件子级)
{
排队。排队(子级);
}
如果(!next.HasChildren&&next是TControl类型的)
{
收益型;
}
}
}
非递归方法总是首选的,因为它们不会耗尽调用堆栈(尽管在这种情况下,无论如何也不太可能)
它的功能基本上与原来的相同:在
while
循环中逐级收集控件。我只将堆栈
替换为队列
,因此控件从上到下返回。当然,还添加了您要查找的条件:筛选类型和排除的容器类型。您尝试的方法有什么问题?我获得了所有控件,即使是tableLayoutPanel中的控件。我无法重现该问题.Concat(controls.Where(ctrl=>ctrl.GetType()!=typeof(TableLayoutPanel)).SelectMany(ctrl=>FindAllChildrenByType(ctrl))
似乎根据需要排除textbox2。这叫什么?请看我的例子,事实上,我已经创建了一个例子来说明我的问题,我没有试图用它来执行程序。实际上,我使用带有用户控件的函数来初始化包含控件的某些属性,并且我已经研究了调用返回的枚举,以查看假定忽略的控件是否已添加到列表中。我想虫子藏在别处了,我会更深入地搜索。。。
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));
}