【问题标题】:Get a Windows Forms control by name in C#在 C# 中按名称获取 Windows 窗体控件
【发布时间】: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。

【问题讨论】:

    标签: c# winforms string controls accessibility


    【解决方案1】:

    使用Control.ControlCollection.Find 方法。

    试试这个:

    this.Controls.Find()
    

    【讨论】:

    • 这对我不起作用。我认为因为正如 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);
                    

                    【讨论】:

                      猜你喜欢
                      • 2011-05-27
                      • 2011-04-23
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多