C# 循环遍历表单的所有控件,甚至是 GroupBox 中的控件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15186828/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loop through all controls of a Form, even those in GroupBoxes
提问by RRM
I'd like to add an event to all TextBoxes on my Form
:
我想向我的所有文本框添加一个事件Form
:
foreach (Control C in this.Controls)
{
if (C.GetType() == typeof(System.Windows.Forms.TextBox))
{
C.TextChanged += new EventHandler(C_TextChanged);
}
}
The problem is that they are stored in several GroupBoxes and my loop doesn't see them. I could loop through controls of each GroupBox
individually but is it possible to do it all in a simple way in one loop?
问题是它们存储在几个 GroupBox 中,而我的循环看不到它们。我可以GroupBox
单独遍历每个控件,但是否可以在一个循环中以一种简单的方式完成所有操作?
回答by christopher
As you have stated, you will have to go deeper than just cycling over each element in your form. This, unfortunately, implies the use of a nested loop.
正如您所说,您必须更深入,而不仅仅是在表单中的每个元素上循环。不幸的是,这意味着使用嵌套循环。
In the first loop, cycle through each element. IF the element is of type GroupBox, then you know you'll need to cycle through each element inside the groupbox, before continuing; else add the event as normal.
在第一个循环中,循环遍历每个元素。如果元素是 GroupBox 类型,那么您知道在继续之前,您需要遍历 groupbox 内的每个元素;否则像往常一样添加事件。
You seem to have a decent grasp of C# so I won't give you any code; purely to ensure you develop all the important concepts that are involved in problem solving :)
您似乎对 C# 掌握得不错,所以我不会给您任何代码;纯粹是为了确保您开发出解决问题所涉及的所有重要概念:)
回答by Olivier Jacot-Descombes
The Controls
collection of Forms and container controls contains only the immediate children. In order to get all the controls, you need to traverse the controls tree and to apply this operation recursively
Controls
窗体和容器控件的集合仅包含直接子项。为了得到所有的控件,你需要遍历控件树并递归地应用这个操作
private void AddTextChangedHandler(Control parent)
{
foreach (Control c in parent.Controls)
{
if (c.GetType() == typeof(TextBox)) {
c.TextChanged += new EventHandler(C_TextChanged);
} else {
AddTextChangedHandler(c);
}
}
}
Note: The form derives (indirectly) from Control
as well and all controls have a Controls
collection. So you can call the method like this in your form:
注意:表单也(间接地)派生自Control
,并且所有控件都有一个Controls
集合。所以你可以在你的表单中调用这样的方法:
AddTextChangedHandler(this);
A more general solution would be to create an extension method that applies an action recursively to all controls. In a static class (e.g. WinFormsExtensions
) add this method:
更通用的解决方案是创建一个扩展方法,将操作递归地应用于所有控件。在静态类(例如WinFormsExtensions
)中添加此方法:
public static void ForAllControls(this Control parent, Action<Control> action)
{
foreach (Control c in parent.Controls) {
action(c);
ForAllControls(c, action);
}
}
The static classes namespace must be "visible", i.e., add an appropriate using
declaration if it is in another namespace.
静态类命名空间必须是“可见的”,即,using
如果它在另一个命名空间中,则添加适当的声明。
Then you can call it like this, where this
is the form; you can also replace this
by a form or control variable whose nested controls have to be affected:
那么你可以这样称呼它,this
表格在哪里;您还可以替换this
为必须影响其嵌套控件的表单或控件变量:
this.ForAllControls(c =>
{
if (c.GetType() == typeof(TextBox)) {
c.TextChanged += C_TextChanged;
}
});
回答by Servy
A few simple, general purpose tools make this problem very straightforward. We can create a simple method that will traverse an entire control's tree, returning a sequence of all of it's children, all of their children, and so on, covering all controls, not just to a fixed depth. We could use recursion, but by avoiding recursion it will perform better.
一些简单的通用工具使这个问题变得非常简单。我们可以创建一个简单的方法来遍历整个控件的树,返回它的所有子项、所有子项等的序列,覆盖所有控件,而不仅仅是固定深度。我们可以使用递归,但通过避免递归,它会表现得更好。
public static IEnumerable<Control> GetAllChildren(this Control root)
{
var stack = new Stack<Control>();
stack.Push(root);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control child in next.Controls)
stack.Push(child);
yield return next;
}
}
Using this we can get all of the children, filter out those of the type we need, and then attach the handler veryeasily:
使用这个我们可以得到所有的孩子,过滤掉我们需要的类型,然后很容易地附加处理程序:
foreach(var textbox in GetAllChildren().OfType<Textbox>())
textbox.TextChanged += C_TextChanged;
回答by XDS
Haven't seen anyone using linq and/or yield so here goes:
还没有看到任何人使用 linq 和/或 yield 所以这里是:
public static class UtilitiesX {
public static IEnumerable<Control> GetEntireControlsTree(this Control rootControl)
{
yield return rootControl;
foreach (var childControl in rootControl.Controls.Cast<Control>().SelectMany(x => x.GetEntireControlsTree()))
{
yield return childControl;
}
}
public static void ForEach<T>(this IEnumerable<T> en, Action<T> action)
{
foreach (var obj in en) action(obj);
}
}
You may then use it to your heart's desire:
然后,您可以根据自己的意愿使用它:
someControl.GetEntireControlsTree().OfType<TextBox>().ForEach(x => x.Click += someHandler);
回答by Georg
Try this
尝试这个
AllSubControls(this).OfType<TextBox>().ToList()
.ForEach(o => o.TextChanged += C_TextChanged);
where AllSubControls is
AllSubControls 在哪里
private static IEnumerable<Control> AllSubControls(Control control)
=> Enumerable.Repeat(control, 1)
.Union(control.Controls.OfType<Control>()
.SelectMany(AllSubControls)
);
LINQ is great!
LINQ 很棒!
回答by Ashraf Abusada
you can only loop through open forms in windows forms using form collection for example to set windows start position for all open forms:
您只能使用表单集合循环浏览窗口表单中的打开表单,例如为所有打开的表单设置窗口开始位置:
public static void setStartPosition()
{
FormCollection fc = Application.OpenForms;
foreach(Form f in fc)
{
f.StartPosition = FormStartPosition.CenterScreen;
}
}
回答by Roger
I know that this is an older topic, but would say the code snippet from http://backstreet.ch/coding/code-snippets/mit-c-rekursiv-durch-form-controls-loopen/is a clever solution for this problem.
我知道这是一个较旧的主题,但会说来自http://backstreet.ch/coding/code-snippets/mit-c-rekursiv-durch-form-controls-loopen/的代码片段是一个聪明的解决方案问题。
It uses an extension method for ControlCollection.
它使用 ControlCollection 的扩展方法。
public static void ApplyToAll<T>(this Control.ControlCollection controlCollection, string tagFilter, Action action)
{
foreach (Control control in controlCollection)
{
if (!string.IsNullOrEmpty(tagFilter))
{
if (control.Tag == null)
{
control.Tag = "";
}
if (!string.IsNullOrEmpty(tagFilter) && control.Tag.ToString() == tagFilter && control is T)
{
action(control);
}
}
else
{
if (control is T)
{
action(control);
}
}
if (control.Controls != null && control.Controls.Count > 0)
{
ApplyToAll(control.Controls, tagFilter, action);
}
}
}
Now, to assign an event to all the TextBox controls you can write a statement like (where 'this' is the form):
现在,要将事件分配给所有 TextBox 控件,您可以编写如下语句(其中“this”是表单):
this.Controls.ApplyToAll<TextBox>("", control =>
{
control.TextChanged += SomeEvent
});
Optionally you can filter the controls by their tags.
您可以选择按标签过滤控件。
回答by Bogdan Doicin
Updated answer:
更新的答案:
I needed to disable all the controls in a form, including groupboxes. This code worked:
我需要禁用表单中的所有控件,包括分组框。此代码有效:
private void AlterControlsEnable(bool ControlEnabled)
{
foreach (Control i in Controls)
i.Enabled = ControlEnabled;
}