Было бы лучше, если бы вы предоставили a good, minimal, complete code example, что четко показывает ваши конкретные cenario. Однако, основываясь на информации, добавленной вами к вашему вопросу, я смог создать то, что, по моему мнению, является примером репрезентативного кода. Этот ответ основан на этом примере.
В качестве комментатора LarsTech отмечает, что ToolStripStatusLabel
не наследует Control
. Наиболее конкретным базовым классом, разделяемым Control
и ToolStripStatusLabel
, является Component
. Поэтому, по крайней мере, у вас есть большая проблема с вашей целью вернуть объект типа Control
и все же найти экземпляр ToolStripStatusLabel
. Даже если вы нашли объект, вы не сможете его отличить до Control
.
Другая проблема заключается в том, что в то время как ToolStrip
сам делает наследуют Control
класс, он не хранит своих детей в собственность Controls
(т.е. в ControlCollection
объекта). Я предполагаю, что это потому, что его дети не являются объектами Control
и поэтому не могут быть сохранены в ControlCollection
. В любом случае это означает, что по мере того, как вы рекурсивно просматриваете графику объекта вашей формы, вы должны обрабатывать ToolStrip
иначе, чем другие экземпляры Control
, чтобы найти своих детей.
Вот пример программа, которая демонстрирует один подход, который будет работать (см в нижней части этого поста для дизайнера сгенерированного кода, который идет с этим примером):
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
детей в форме, во всяком случае, я бы не советовал вкладывать много усилий в действительно обобщенном решении. Лучше обращаться с отдельными случаями по мере необходимости, чтобы напомнить себе, что то, что вы делаете, на самом деле не такая хорошая идея.:)
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;
}
Что произошло, когда вы активизировали через код в отладчике? Получил ли код какой-либо из рассматриваемых контейнеров? Если да, то что произошло, когда оператор 'foreach' попытался перечислить дочерний элемент контейнера? Код, который вы опубликовали, прост и должен работать нормально. Таким образом, ваша проблема заключается в коде, который вы не опубликовали. Предоставьте [хороший, _minimal_, _complete_ пример кода] (https://stackoverflow.com/help/mcve), который надежно воспроизводит проблему. –
Это все код. Это простая рекурсивная функция, которая должна найти элемент управления по его имени. Отладчик корректно выполняет итерацию всех форм-корневых элементов управления, которые не являются контейнерами управления. Я вижу их имена и атрибуты без проблем. Когда шаг в некоторые контейнеры обычно отображает пустую строку для имени и атрибутов. Просто упомянуть, что я пробовал с
_ «Это все код» _ - если вы имеете в виду «это все ** код **», то это явно неверно. Пожалуйста, прочитайте страницу по ссылке, которую я предоставил, чтобы увидеть, что подразумевается под ** минимальным ** и ** полным **, а также для объяснения причин такого примера кода. –