在 C# 中按名称获取 Windows 窗体控件

Posted

技术标签:

【中文标题】在 C# 中按名称获取 Windows 窗体控件【英文标题】:Get a Windows Forms control by name in C# 【发布时间】:2010-12-04 22:29:37 【问题描述】:

我有一个名为myMenuToolStripMenuItem。我怎样才能像这样访问它:

/* Normally, I would do: */
this.myMenu... etc.

/* But how do I access it like this: */
String name = myMenu;
this.name...

这是因为我正在从 XML 文件动态生成 ToolStripMenuItems,并且需要通过动态生成的名称来引用 MenuItems。

【问题讨论】:

【参考方案1】:

使用Control.ControlCollection.Find 方法。

试试这个:

this.Controls.Find()

【讨论】:

msdn.microsoft.com/en-us/library/… 这对我不起作用。我认为因为正如 o3o 所指出的,ToolStripMenuItem 不是控件。 对于文本框,我必须转换为控件类型并采用这样的第一个元素:((TextBox) frm.Controls.Find("controlName",true)[0]).Text = "yay"; @DanW 这很像 Java 如果我有一部分名称并且我需要一个名称中包含该字符串的控件列表怎么办?【参考方案2】:
string name = "the_name_you_know";

Control ctn = this.Controls[name];

ctn.Text = "Example...";

【讨论】:

ToolStripMenuItem 的唯一问题是它不是控件,您的代码将无法工作。 ;( 其实这个答案更接近我的问题。【参考方案3】:
Control GetControlByName(string Name)

    foreach(Control c in this.Controls)
        if(c.Name == Name)
            return c;

    return null;

不管这个,我重新发明***。

【讨论】:

比 Julien 的解决方案更通用。不过仍然可以正常工作。 这不是重新发明***,这是一个很好的解决方案,可以轻松适应您不知道控件名称或想要查看每个控件的名称或执行许多访问操作的情况控制,因此对我很有用。【参考方案4】:

假设你有 menuStrip 对象并且菜单只有一层,使用:

ToolStripMenuItem item = menuStrip.Items
    .OfType<ToolStripMenuItem>()
    .SelectMany(it => it.DropDownItems.OfType<ToolStripMenuItem>())
    .SingleOrDefault(n => n.Name == "MyMenu");

对于更深的菜单级别,请在语句中添加更多 SelectMany 运算符。

如果要搜索条中的所有菜单项,请使用

ToolStripMenuItem item = menuStrip.Items
    .Find("MyMenu",true)
    .OfType<ToolStripMenuItem>()
    .Single();

但是,请确保每个菜单具有不同的名称以避免重复键引发异常。

为避免出现异常,您可以使用FirstOrDefault 而不是SingleOrDefault / Single,或者如果您可能有Name 重复,则只返回一个序列。

【讨论】:

【参考方案5】:

使用与Philip Wallace相同的方法,我们可以这样做:

    public Control GetControlByName(Control ParentCntl, string NameToSearch)
    
        if (ParentCntl.Name == NameToSearch)
            return ParentCntl;

        foreach (Control ChildCntl in ParentCntl.Controls)
        
            Control ResultCntl = GetControlByName(ChildCntl, NameToSearch);
            if (ResultCntl != null)
                return ResultCntl;
        
        return null;
    

例子:

    public void doSomething() 
    
            TextBox myTextBox = (TextBox) this.GetControlByName(this, "mytextboxname");
            myTextBox.Text = "Hello!";
    

希望对你有帮助! :)

【讨论】:

【参考方案6】:

this.Controls.Find(name, searchAllChildren) 没有找到 ToolStripItem,因为 ToolStripItem 不是控件

  using SWF = System.Windows.Forms;
  using NUF = NUnit.Framework;
  namespace workshop.findControlTest 
     [NUF.TestFixture]
     public class FormTest 
        [NUF.Test]public void Find_menu() 
           // == prepare ==
           var fileTool = new SWF.ToolStripMenuItem();
           fileTool.Name = "fileTool";
           fileTool.Text = "File";

           var menuStrip = new SWF.MenuStrip();
           menuStrip.Items.Add(fileTool);

           var form = new SWF.Form();
           form.Controls.Add(menuStrip);

           // == execute ==
           var ctrl = form.Controls.Find("fileTool", true);

           // == not found! ==
           NUF.Assert.That(ctrl.Length, NUF.Is.EqualTo(0)); 
        
     
  

【讨论】:

【参考方案7】:

最好的方法之一是这样一行代码:

在此示例中,我们在表单中按名称搜索所有 PictureBox

PictureBox[] picSample = 
                    (PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true);

最重要的是find的第二个参数。

如果您确定控件名称存在,您可以直接使用它:

  PictureBox picSample = 
                        (PictureBox)this.Controls.Find(PIC_SAMPLE_NAME, true)[0];

【讨论】:

【参考方案8】:
this.Controls["name"];

这是实际运行的代码:

public virtual Control this[string key]

    get
    
        if (!string.IsNullOrEmpty(key))
        
            int index = this.IndexOfKey(key);
            if (this.IsValidIndex(index))
            
                return this[index];
            
        
        return null;
    

对比:

public Control[] Find(string key, bool searchAllChildren)

    if (string.IsNullOrEmpty(key))
    
        throw new ArgumentNullException("key", SR.GetString("FindKeyMayNotBeEmptyOrNull"));
    
    ArrayList list = this.FindInternal(key, searchAllChildren, this, new ArrayList());
    Control[] array = new Control[list.Count];
    list.CopyTo(array, 0);
    return array;


private ArrayList FindInternal(string key, bool searchAllChildren, Control.ControlCollection controlsToLookIn, ArrayList foundControls)

    if ((controlsToLookIn == null) || (foundControls == null))
    
        return null;
    
    try
    
        for (int i = 0; i < controlsToLookIn.Count; i++)
        
            if ((controlsToLookIn[i] != null) && WindowsFormsUtils.SafeCompareStrings(controlsToLookIn[i].Name, key, true))
            
                foundControls.Add(controlsToLookIn[i]);
            
        
        if (!searchAllChildren)
        
            return foundControls;
        
        for (int j = 0; j < controlsToLookIn.Count; j++)
        
            if (((controlsToLookIn[j] != null) && (controlsToLookIn[j].Controls != null)) && (controlsToLookIn[j].Controls.Count > 0))
            
                foundControls = this.FindInternal(key, searchAllChildren, controlsToLookIn[j].Controls, foundControls);
            
        
    
    catch (Exception exception)
    
        if (ClientUtils.IsSecurityOrCriticalException(exception))
        
            throw;
        
    
    return foundControls;

【讨论】:

ClientUtils.IsSecurityOrCriticalException 是什么?【参考方案9】:

假设您有 Windows.Form Form1 作为父表单,它拥有您创建的菜单。表单的属性之一被命名为.Menu。如果菜单是通过程序创建的,它应该是相同的,并且会被识别为菜单并放置在 Form 的 Menu 属性中。

在这种情况下,我有一个名为 File 的主菜单。在File 下称为MenuItem 的子菜单包含标签Open,并命名为menu_File_Open。以下工作。假设你

// So you don't have to fully reference the objects.
using System.Windows.Forms;

// More stuff before the real code line, but irrelevant to this discussion.

MenuItem my_menuItem = (MenuItem)Form1.Menu.MenuItems["menu_File_Open"];

// Now you can do what you like with my_menuItem;

【讨论】:

【参考方案10】:

您可以在 Form 类中使用查找功能。如果你想投射 (Label) ,(TextView) ... 等,这样你就可以使用对象的特殊功能。它将返回 Label 对象。

(Label)this.Controls.Find(name,true)[0];

名称:表单中搜索到的项目名称

true:搜索所有 Children 布尔值

【讨论】:

【参考方案11】:

由于您是动态生成的,因此请在字符串和菜单项之间保留一个映射,以便快速检索。

// in class scope
private readonly Dictionary<string, ToolStripMenuItem> _menuItemsByName = new Dictionary<string, ToolStripMenuItem>();

// in your method creating items
ToolStripMenuItem createdItem = ...
_menuItemsByName.Add("<name here>", createdItem);

// to access it
ToolStripMenuItem menuItem = _menuItemsByName["<name here>"];

【讨论】:

现在有一个想法! +1(尽管仅当控件已在字典中时才有效)【参考方案12】:

查看 ToolStrip.Items 集合。它甚至还有一个 find 方法可用。

【讨论】:

【参考方案13】:

您可以执行以下操作:

私有 ToolStripMenuItem getToolStripMenuItemByName(string nameParam) foreach(this.Controls 中的控制 ctn) 如果(ctn 是 ToolStripMenuItem) if (ctn.Name = nameParam) 返回ctn; 返回空值;

【讨论】:

【参考方案14】:

一个简单的解决方案是在foreach 循环中遍历Controls 列表。像这样的:

foreach (Control child in Controls)

    // Code that executes for each control.

所以现在你有了你的迭代器child,它的类型是Control。现在做你想做的事,我个人在我之前做的一个项目中发现了这个,它为此控件添加了一个事件,如下所示:

child.MouseDown += new MouseEventHandler(dragDown);

【讨论】:

以上是关于在 C# 中按名称获取 Windows 窗体控件的主要内容,如果未能解决你的问题,请参考以下文章

在C# WinForm应用程序中如何获取当前窗体中被激发的控件名称?

c#如何创建/设置windows窗体用户控件属性获取简单消息弹窗

C#获取当前窗体句柄及该窗体里的信息

C# Winform 控件或窗体失去焦点时,获取键盘输入数据(我用winform获取另一个窗口的数据)

如何在 C# 中获取当前可执行文件的名称?

c# 用 FindWindowEx 获取子窗体时 出异常