简体   繁体   English

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

[英]Get a Windows Forms control by name in C#

I have a ToolStripMenuItem called myMenu .我有一个名为myMenuToolStripMenuItem How can I access this like so:我怎样才能像这样访问它:

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

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

This is because I am dynamically generating ToolStripMenuItems from an XML file and need to reference MenuItems by their dynamically generated names.这是因为我从 XML 文件动态生成 ToolStripMenuItems,并且需要通过动态生成的名称引用 MenuItems。

Use the Control.ControlCollection.Find method.使用Control.ControlCollection.Find方法。

Try this:试试这个:

this.Controls.Find()
string name = "the_name_you_know";

Control ctn = this.Controls[name];

ctn.Text = "Example...";
Control GetControlByName(string Name)
{
    foreach(Control c in this.Controls)
        if(c.Name == Name)
            return c;

    return null;
}

Disregard this, I reinvent wheels.无视这一点,我重新发明轮子。

Assuming you have the menuStrip object and the menu is only one level deep, use:假设您有menuStrip对象并且菜单只有一层深,请使用:

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

For deeper menu levels add more SelectMany operators in the statement.对于更深的菜单级别,请在语句中添加更多 SelectMany 运算符。

if you want to search all menu items in the strip then use如果要搜索条带中的所有菜单项,请使用

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

However, make sure each menu has a different name to avoid exception thrown by key duplicates.但是,请确保每个菜单都有不同的名称,以避免重复键引发异常。

To avoid exceptions you could use FirstOrDefault instead of SingleOrDefault / Single , or just return a sequence if you might have Name duplicates.为避免异常,您可以使用FirstOrDefault而不是SingleOrDefault / Single ,或者如果您可能有Name重复,则只返回一个序列。

Using the same approach of Philip Wallace , we can do like this:使用与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;
    }

Example:例子:

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

I hope it help!我希望它有帮助! :) :)

this.Controls.Find(name, searchAllChildren) doesn't find ToolStripItem because ToolStripItem is not a Control 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)); 
        }
     }
  }

One of the best way is a single row of code like this:最好的方法之一是单行代码,如下所示:

In this example we search all PictureBox by name in a form在此示例中,我们在表单中按名称搜索所有PictureBox

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

Most important is the second paramenter of find .最重要的是find的第二个参数。

if you are certain that the control name exists you can directly use it:如果您确定控件名称存在,您可以直接使用它:

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

This is the actual code that is ran:这是运行的实际代码:

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;
    }
}

vs:与:

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;
}

You can use find function in your Form class.您可以在 Form 类中使用 find 函数。 If you want to cast (Label) ,(TextView) ... etc, in this way you can use special features of objects.如果你想投射 (Label) ,(TextView) ... 等,这样你就可以使用对象的特殊功能。 It will be return Label object.它将返回 Label 对象。

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

name : item name of searched item in the form name : 表单中搜索项目的项目名称

true : Search all Children boolean value true : 搜索所有 Children 布尔值

Assuming you have Windows.Form Form1 as the parent form which owns the menu you've created.假设您有Windows.Form Form1作为拥有您创建的菜单的父窗体。 One of the form's attributes is named .Menu .表单的属性之一被命名为.Menu If the menu was created programmatically, it should be the same, and it would be recognized as a menu and placed in the Menu attribute of the Form.如果菜单是通过编程方式创建的,它应该是相同的,并且会被识别为菜单并放置在 Form 的 Menu 属性中。

In this case, I had a main menu called File .在这种情况下,我有一个名为File的主菜单。 A sub menu, called a MenuItem under File contained the tag Open and was named menu_File_Open . File下称为MenuItem的子菜单包含标签Open并命名为menu_File_Open The following worked.以下工作。 Assuming you假设你

// 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;

Since you're generating them dynamically, keep a map between a string and the menu item, that will allow fast retrieval.由于您是动态生成它们,因此请在字符串和菜单项之间保留一个映射,以便快速检索。

// 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>"];

Have a look at the ToolStrip.Items collection.查看 ToolStrip.Items 集合。 It even has a find method available.它甚至有一个可用的查找方法。

You can do the following:您可以执行以下操作:

private ToolStripMenuItem getToolStripMenuItemByName(string nameParam)
   {
      foreach (Control ctn in this.Controls)
         {
            if (ctn is ToolStripMenuItem)
               {
                   if (ctn.Name = nameParam)
                      {
                         return ctn;
                      }
                }
         }
         return null;
    }

A simple solution would be to iterate through the Controls list in a foreach loop.一个简单的解决方案是在foreach循环中遍历Controls列表。 Something like this:像这样的东西:

foreach (Control child in Controls)
{
    // Code that executes for each control.
}

So now you have your iterator, child , which is of type Control .所以现在你有了你的迭代器child ,它的类型是Control Now do what you will with that, personally I found this in a project I did a while ago in which it added an event for this control, like this:现在做你想做的事,我个人在我之前做的一个项目中发现了这个,它为此控件添加了一个事件,如下所示:

child.MouseDown += new MouseEventHandler(dragDown);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM