c# - 如何获取WinForm上所有控件的列表,包括SplitContainers或Panels中的控件

标签 c# winforms controls splitcontainer statusstrip

在我的WinForm上有几个容器,例如Panel,SpliContainer,StatusStrip...。这些容器中的每一个都包含诸如按钮或文本框之类的基本元素。我需要遍历所有表单控件(甚至包括Panels,SplitContainers,StatusStrip中的控件)以找到一些控件。我尝试递归功能

    ListAllControls(Control MainControl)
    {
        foreach (Control control in MainControl.Controls)
        {
            if (control.HasChildren)
            {
                ListAllControls(control);
            }
            else
            { 
                // do something with this control
            }
        }
    }


但我没有容器中的控件!

更新:

我有一个包含SplitContainer,Panel和StatuStrip的表单。在每个控件中,我都有几个子控件,例如StatuStrip1中的toolStripStatusLabel1。问题是,当我尝试通过功能ListAllControls在StatuStrip中找到例如control toolStripStatusLabel1时,我找不到它!我不知道从表单获取所有控件的任何其他方法。完整的代码在这里:

class Control_Finder
{

    private Control founded_control = null;

    public Control Founded_Control
    {
        get { return founded_control; }
    }

    public void ListAllControls(Control MainControl, string SearchForControl)
    {
        foreach (Control control in MainControl.Controls)
        {
            if (control.HasChildren)
            {
                ListAllControls(control, SearchForControl);
            }
            else
            {
                // check if control has searched name
                if (control.Name == SearchForControl)
                {
                    founded_control = control;
                    return;
                }
            }
        }
    }
} // class


样品:

Form Me = this;
Control_Finder Test = new Control_Finder();
Test.ListAllControls(Me, "toolStripStatusLabel1");

if (Test.Founded_Control != null)
{
      MessageBox.Show("I found control " + Test.Founded_Control.Name + "!");
}
else
{
      MessageBox.Show("Didn't found! :(");
}


对于此示例,我得到未找到:(但是,如果我使用StatusStrip1,则会得到“我找到了控件StatusStrip1!”。
我希望现在的问题比以前更明确。

最佳答案

最好提供a good, minimal, complete code example清楚地显示您的特定情况。但是,根据您添加到问题中的信息,我能够创建我认为是代表性的代码示例。该答案基于该示例。


正如评论员LarsTech所指出的,ToolStripStatusLabel不继承ControlControlToolStripStatusLabel共享的最特定的基类是Component。因此,至少,在尝试返回类型为Control的对象而仍然找到ToolStripStatusLabel实例的过程中,您遇到了一个大问题。即使找到了对象,也无法将其强制转换为Control

另一个问题是,尽管ToolStrip本身确实继承了Control类,但它没有将其子级存储在Controls属性中(即,存储在ControlCollection对象中)。我认为这是因为其子对象不是Control对象,因此无法存储在ControlCollection中。无论如何,这意味着递归遍历表单的对象图时,您必须以不同于其他ToolStrip实例的方式处理Control才能找到其子级。


这是一个示例程序,演示了一种可行的方法(有关此示例的Designer生成的代码,请参见本文的底部):

Form1.cs:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Component component = FindControl(this.Controls, "toolStripStatusLabel1");

        label2.Text = component != null ?
            "Found control named \"" + GetNameForComponent(component) + "\"" :
            "No control was found";
    }

    private static string GetNameForComponent(Component component)
    {
        Control control = component as Control;

        if (control != null)
        {
            return control.Name;
        }

        ToolStripItem item = component as ToolStripStatusLabel;

        if (item != null)
        {
            return item.Name;
        }

        return "<unknown Component type>";
    }

    private Component FindControl(IEnumerable controlCollection, string name)
    {
        foreach (Component component in controlCollection)
        {
            if (GetNameForComponent(component) == name)
            {
                return component;
            }

            IEnumerable childControlCollection = GetChildrenForComponent(component);

            if (childControlCollection != null)
            {
                Component result = FindControl(childControlCollection, name);

                if (result != null)
                {
                    return result;
                }
            }
        }

        return null;
    }

    private static IEnumerable GetChildrenForComponent(Component component)
    {
        ToolStrip toolStrip = component as ToolStrip;

        if (toolStrip != null)
        {
            return toolStrip.Items;
        }

        Control control = component as Control;

        if (control != null)
        {
            return control.HasChildren ? control.Controls : null;
        }

        return null;
    }
}


由于要处理的对象的对象继承是不相交的,因此必须进行一些特殊处理:


您找到的项目可能是Control的实例,也可能不是。 Control的实例将其名称存储在Control.Name属性中,但显然不是Control对象的实例不会。需要通过标识存储其名称属性的类型来专门处理它们(在这种情况下为ToolStripItem.Name,但请注意,还有其他非Control类型继承了Component,每种类型都必须进行处理分别)。我添加了一个GetNameForComponent(Component)方法来封装它。
在找到的属于Control实例的项目中,有些项目会将其子项存储在Controls集合中,而另一些则不会,而使用其他一些属性来引用存储子项的集合。同样,提供了一个辅助方法(在本例中为GetChildrenForComponent(Component))来封装此差异。


解决了这两个问题后,可以轻松编写搜索图的基本递归方法。请注意,与您的方法相比,我对方法的基本架构进行了一些更改。我认为,将代码本身作为完整的类来实现是不必要的,在任何情况下,将结果存储在该类的成员中而不是仅由方法返回都是特别错误的。

在我的示例中,我只是将其简单地实现为单个方法,如果找到该对象,该方法将返回有问题的对象。

另外请注意,您的实现找不到任何本身就是对象容器的对象。我在示例中也对此进行了更正。


最后一点:按照上述策略,您必须为每个感兴趣的基类添加代码。上面的内容也许足以满足您的需要,或者您还有其他容纳非Control对象并且不继承ToolStrip的容器类型。如果是这样,您将不得不在每种适用于这些类型的帮助器方法中添加其他案例。

一种替代方法是使用反射来查找包含例如名字和孩子。假设名称始终存储在名为Name的属性中,则该部分将相对简单。

但是即使在这个简单的示例中,使用反射来获取子对象也相当复杂。而不是子代始终处于从名为例如的属性获得的集合对象中。 Controls,在一种情况下是名称,在另一种情况下,名称是Items。一个人可以更深入地挖掘例如确定在集合中找到的对象的类型,但是此时代码开始变得过于复杂。

鉴于以某种形式将ToolStrip儿童与普通Control儿童同等对待是否真的有意义尚有待商I,我不建议在真正通用的解决方案上投入大量精力。最好根据需要处理个别案件,以提醒自己自己做的事情实际上并不是一个好主意。 :)


Form1.Designer.cs:

partial class Form1
{
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.statusStrip1 = new System.Windows.Forms.StatusStrip();
        this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
        this.button1 = new System.Windows.Forms.Button();
        this.label1 = new System.Windows.Forms.Label();
        this.label2 = new System.Windows.Forms.Label();
        this.statusStrip1.SuspendLayout();
        this.SuspendLayout();
        // 
        // statusStrip1
        // 
        this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
        this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
        this.toolStripStatusLabel1});
        this.statusStrip1.Location = new System.Drawing.Point(0, 228);
        this.statusStrip1.Name = "statusStrip1";
        this.statusStrip1.Size = new System.Drawing.Size(282, 25);
        this.statusStrip1.TabIndex = 0;
        this.statusStrip1.Text = "statusStrip1";
        // 
        // toolStripStatusLabel1
        // 
        this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
        this.toolStripStatusLabel1.Size = new System.Drawing.Size(111, 20);
        this.toolStripStatusLabel1.Text = "Strip status text";
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(12, 12);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(75, 23);
        this.button1.TabIndex = 1;
        this.button1.Text = "button1";
        this.button1.UseVisualStyleBackColor = true;
        this.button1.Click += new System.EventHandler(this.button1_Click);
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(12, 38);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(52, 17);
        this.label1.TabIndex = 2;
        this.label1.Text = "Result:";
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(70, 38);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(0, 17);
        this.label2.TabIndex = 3;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(282, 253);
        this.Controls.Add(this.label2);
        this.Controls.Add(this.label1);
        this.Controls.Add(this.button1);
        this.Controls.Add(this.statusStrip1);
        this.Name = "Form1";
        this.Text = "Form1";
        this.statusStrip1.ResumeLayout(false);
        this.statusStrip1.PerformLayout();
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.StatusStrip statusStrip1;
    private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Label label2;
}

关于c# - 如何获取WinForm上所有控件的列表,包括SplitContainers或Panels中的控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32832981/

相关文章:

C# XML 同一元素多次出现

c++ - Windows C++ 子窗口无响应

c# - winforms html 编辑器

c# - Winform 模板系统,如 ASP.NET MasterPage 或 MS Access SubForm

c# - 为什么 Math.Round/Floor/Ceiling 不返回 long 或 int?

c# - 当类的属性成员不是原始类型时,如何实例化一个类?

找不到 C# SqlConnection

c# - 委托(delegate)事件

c# - WinForms:如何防止面板随窗口内容滚动?

forms - Excel VBA 中的现代表单和表单控件