Могу ли я оценить две группы элементов с циклом foreach в C# winforms?

у меня есть WinForms TabControl, и я пытаюсь выполнить цикл через все элементы управления, содержащиеся в каждой вкладке. Есть ли способ добавить and на foreach цикл или невозможно оценить более одной группы элементов? Например, это то, что я хотел бы сделать:

foreach (Control c in tb_Invoices.Controls and tb_Statements.Controls)
{
    //do something
}

или

foreach (Control c in tb_Invoices.Controls, tb_Statements.Controls)
{
    //do something
}

возможно ли это, и если нет, то это следующая лучшая вещь? Мне нужно использовать for петли?

6 ответов


foreach(TabPage page in yourTabControl.TabPages){
   foreach(Control c in page.Controls){
      LoopThroughControls(c);
   }  
}

private void LoopThroughControls(Control parent){
   foreach(Control c in parent.Controls)
      LoopThroughControls(c);
}

окончательное решение:

var allControls = from TabPage p in tabControl.TabPages
                  from Control c in p.Controls
                  select c;

оригинальный ответ - использовать Concat:

var allControls = tb_Invoices.Controls.Cast<Control>()
                             .Concat(tb_Statements.Controls.Cast<Control>();

кстати, я думаю, что лучше использовать простой не общий ArrayList здесь

ArrayList allControls = new ArrayList();
allControls.AddRange(tb_Invoices.Controls);
allControls.AddRange(tb_Statements.Controls);

что мне нравится делать, так это:

var list = new List<T>();
list.AddRange(list1);
list.AddRange(list2);
list.AddRange(list3);
list.AddRange(list4);

foreach (T item in list)
{
    .....
}

вы можете использовать один цикл foreach, написав его рекурсивно. Это позволит перебрать все элементы управления всех типов в форме.

private void LoopAllControls(Control YourObject)
   foreach(Control c in YourObject.Controls)
   {
      if(C.Controls.Count > 0)
        LoopAllControls(c.Controls);
      //your code
   }

вы могли бы сделать:

public static void ForAllChildren(Action<Control> action, 
    params Control[] parents)
{
    foreach(var p in parents)
        foreach(Control c in p.Controls)
            action(c);
}

называется так:

ForAllChildren(x => Foo(x), tb_Invoices, tb_Statements);

вы можете быть немного поражены производительностью для вызова действия, хотя в этом случае вы можете просто использовать вложенный foreach:

foreach (var p in new Control[] { tb_Invoices, tb_Statements })
    foreach (Control c in p.Controls)
        Foo(c);

аналогично, универсального решения для перебора всех элементов в любой необщего IEnumerable может быть (хотя немного похоже на использование кувалды для забивания гвоздя):

public static void ForEachAll<T>(Action<T> action, 
    params System.Collections.IEnumerable[] collections)
{
    foreach(var collection in collections)
        foreach(var item in collection.Cast<T>())
            action(item);
}

называется так:

ForEachAll<Control>(x => Foo(x), tb_Invoices.Controls, tb_Statements.Controls);

если вы не в состоянии использовать LINQ (например, застрял .NET2), я предлагаю вам использовать этот метод:

public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] args)
{
    foreach (IEnumerable<T> collection in args)
    {
        foreach (T item in collection)
        {
            yield return item;
        }
    }
}

теперь у вас есть общая функция, которую вы можете использовать с что-нибудь вот перечисли. Ваш цикл может выглядеть так:

foreach (Control c in Concat(tb_Invoices.Controls, tb_Statements.Controls))
{
    //do something
}

простой, дешевый и выразительный!

EDIT: если ваша коллекция не реализует IEnumerable<T>, но только IEnumerable, вы можете добавить перегрузку, которая примет последнее. Все остается по-прежнему, за исключением того, что T изменения object во вложенном цикле.