我想将事件添加到我的窗体上的所有文本框:
foreach (Control C in this.Controls)
{
if (C.GetType() == typeof(System.Windows.Forms.TextBox))
{
C.TextChanged += new EventHandler(C_TextChanged);
}
}
问题是,它们存储在几个groupboxes和我的循环没有看到他们。 我可以通过单独的每个组合框中的控制环,但它可以做到这一切在一个简单的方法在一个循环?
该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);
}
}
}
注意:形式导出(间接地)从Control
以及和所有的控制有Controls
集合。 所以,你可以这样调用该方法在你的表格:
AddTextChangedHandler(this);
一个更普遍的解决方案是创建一个递归的应用一个动作的所有控件的扩展方法。 在一个静态类(如WinFormsExtensions
)添加这个方法:
public static void ForAllControls(this Control parent, Action<Control> action)
{
foreach (Control c in parent.Controls) {
action(c);
ForAllControls(c, action);
}
}
静态类的命名空间必须是“看得见”,即加入适量using
声明如果是在另一个命名空间。
然后,你可以这样调用,在this
为形式; 你也可以更换this
表格或控制变量,其嵌套控件都受到影响:
this.ForAllControls(c =>
{
if (c.GetType() == typeof(TextBox)) {
c.TextChanged += C_TextChanged;
}
});
几个简单的,通用的工具,使这个问题非常简单。 我们可以创建一个简单的方法,将遍历整个控制的树,返回所有它的孩子的序列,所有的孩子,等等,涵盖了所有的控制,而不仅仅是一个固定的深度。 我们可以使用递归,但避免递归它会表现得更好。
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;
}
}
利用这一点,我们可以得到所有的孩子,过滤掉那些我们需要的类型,然后很容易地安装处理程序:
foreach(var textbox in GetAllChildren().OfType<Textbox>())
textbox.TextChanged += C_TextChanged;
试试这个
AllSubControls(this).OfType<TextBox>().ToList()
.ForEach(o => o.TextChanged += C_TextChanged);
其中AllSubControls是
private static IEnumerable<Control> AllSubControls(Control control)
=> Enumerable.Repeat(control, 1)
.Union(control.Controls.OfType<Control>()
.SelectMany(AllSubControls)
);
LINQ是伟大的!
没见过使用LINQ和/或产量所以这里去的人:
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);
}
}
然后,您可以用它来你的心脏的欲望:
someControl.GetEntireControlsTree().OfType<TextBox>().ForEach(x => x.Click += someHandler);
正如你所说,你将不得不去的不仅仅是骑自行车在表单中的每个元素更深。 很不幸,意味着使用一个嵌套循环。
在第一个循环中,循环通过每个元件。 如果元素的类型分组框中的,那么你就知道你会通过组框内部的每个元素需要周期,继续之前; 否则添加事件为正常。
你似乎有C#一个体面的把握,所以我不会给你任何代码; 纯粹以确保您所有的开发中所涉及的问题解决:)的重要概念
你只能通过使用形式征收例如Windows窗体打开的窗体回路设置窗口全部打开的窗体开始位置:
public static void setStartPosition()
{
FormCollection fc = Application.OpenForms;
foreach(Form f in fc)
{
f.StartPosition = FormStartPosition.CenterScreen;
}
}
我知道这是一个老话题,但要说从代码片段http://backstreet.ch/coding/code-snippets/mit-c-rekursiv-durch-form-controls-loopen/是这个聪明的解决方案问题。
它使用的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);
}
}
}
现在,分配给所有的TextBox控件,你可以写像(其中“这”是表格)声明的事件:
this.Controls.ApplyToAll<TextBox>("", control =>
{
control.TextChanged += SomeEvent
});
您也可以选择通过他们的标签过滤控制。