Общий рекурсивный метод для итерации всех элементов управления и связанных с ними элементов управления в форме окна
Есть ли какой-нибудь общий рекурсивный метод, который может выполнять итерацию всех элементов управления (включая 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