在窗体中迭代所有控件及其相关控件的通用递归方法

Posted

技术标签:

【中文标题】在窗体中迭代所有控件及其相关控件的通用递归方法【英文标题】:General recursive method for iterate all controls and their related controls in a windows form 【发布时间】:2013-01-07 04:22:23 【问题描述】:

是否有任何通用递归方法可以在 Windows 窗体中迭代所有控件(包括工具条及其项、绑定导航器及其项...)? (其中一些不是从 Control 类继承的)或至少迭代工具条及其项、绑定导航器及其项?

【问题讨论】:

【参考方案1】:

您将在这里遇到障碍,因为ToolStrip 使用Items 而不是Controls,并且ToolStripItem 不继承自ControlToolStripItemControl 都继承自 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...

不幸的是,您将进行大量手动类型检查和强制转换。

【讨论】:

【参考方案2】:

在这种情况下我通常会这样做:

首先定义一个接受 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);
    

现在您可以将要为每个控件执行的代码放在一个方法中,并通过委托在 Form 上调用它:

private void DoStg(Control c)

    // whatever you want


RecursivelyDoOnControls(new DoSomethingWithControl(DoStg), yourForm);

编辑:

由于您也在处理 ToolStripItems,因此您可以定义委托来处理通用对象,然后编写递归方法的不同重载。 IE。像这样:

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

【讨论】:

但是一些对象比如toolstripbuttons是从Control类继承来的。

以上是关于在窗体中迭代所有控件及其相关控件的通用递归方法的主要内容,如果未能解决你的问题,请参考以下文章

Delphi Excel导入 的通用程序

窗体内元素遍历-通用方法(DevExpress 中BarManager的遍历)

如何遍历winform窗体中的所有控件

通用控制 - 关于码头和锚点的简单问题

VBA迭代主窗体上的控件,同时忽略子窗体

在C#winform中如何遍历子窗体中有容器中的所有的控件