Общий рекурсивный метод для итерации всех элементов управления и связанных с ними элементов управления в форме окна

Есть ли какой-нибудь общий рекурсивный метод, который может выполнять итерацию всех элементов управления (включая toolstrip и его элементы, bindingnavigator и его элементы,...) в форме окна? (некоторые из них не унаследованы от класса Control) или, по крайней мере, повторять toolstrip и его элементы, bindingnavigator и его элементы?

2 ответа

Решение

Вы столкнетесь с загадкой здесь, потому что ToolStrip использования Items вместо Controls, а также ToolStripItem не наследуется от Control, И то и другое ToolStripItem а также Control наследовать от Componentтак что в лучшем случае вы можете получить IEnumerable<Component>,

Вы можете сделать это с помощью следующего метода расширения:

public static class ComponentExtensions
{
    public static IEnumerable<Component> GetAllComponents(this Component component)
    {
        IEnumerable<Component> components;
        if (component is ToolStrip) components = ((ToolStrip)component).Items.Cast<Component>();
        else if (component is Control) components = ((Control)component).Controls.Cast<Component>();
        else components = Enumerable.Empty<Component>();    //  figure out what you want to do here
        return components.Concat(components.SelectMany(x => x.GetAllComponents()));
    }
}

В форме Windows вы можете обработать все эти компоненты в foreach цикл:

foreach (Component component in this.GetAllComponents())
{
    //    Do something with component...
}

К сожалению, вы будете делать много ручной проверки типов и приведения типов.

Вот что я обычно делаю в этом случае:

Прежде всего, определите делегата, который принимает Control в качестве параметра:

public delegate void DoSomethingWithControl(Control c);

Затем реализуйте метод, который принимает этот делегат в качестве первого параметра, и элемент управления, для которого он будет рекурсивно выполняться как второй. Этот метод сначала выполняет делегат, а затем зацикливает коллекцию Controls элемента управления для рекурсивного вызова самого себя. Это работает, так как Controls определен в Control и возвращает пустую коллекцию для простых элементов управления, таких как:

public void RecursivelyDoOnControls(DoSomethingWithControl aDel, Control aCtrl)
{
    aDel(aCtrl);
    foreach (Control c in aCtrl.Controls)
    {
        RecursivelyDoOnControls(aDel, c);
    }
}

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

private void DoStg(Control c)
{
    // whatever you want
}

RecursivelyDoOnControls(new DoSomethingWithControl(DoStg), yourForm);

РЕДАКТИРОВАТЬ:

Поскольку вы также имеете дело с ToolStripItems, вы можете определить делегат для работы с универсальными объектами, а затем написать различные перегрузки рекурсивного метода. Т.е. как то так:

public delegate void DoSomethingWithObject(Object o);

public void RecursivelyDo(DoSomethingWithObject aDel, Control aCtrl)
{
    aDel(aCtrl);
    foreach (Control c in aCtrl.Controls)
    {
        RecursivelyDoOnControls(aDel, c);
    }
}

public void RecursivelyDo(DoSomethingWithObject aDel, ToolStrip anItem)
{
    aDel(anItem);
    foreach (ToolstripItem c in anItem.Items)
    {
        RecursivelyDo(aDel, c);
    }
}

public void RecursivelyDo(DoSomethingWithObject aDel, ToolStripDropDownButton anItem)
{
    aDel(anItem);
    foreach (ToolStripItem c in anItem.DropDownItems)
    {
        RecursivelyDo(aDel, c);
    }
}

//and so on
Другие вопросы по тегам