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

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

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


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

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

240991 次浏览

使用 控制,控制收集,查找方法。

试试这个:

this.Controls.Find()
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;


return null;
}

不管这个,我重新发明轮子。

由于您是动态生成它们的,所以在字符串和菜单项之间保持映射,这将允许快速检索。

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

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

你可以这样做:

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


Control ctn = this.Controls[name];


ctn.Text = "Example...";
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;
}
}

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

Find (name,searchAllChildren) 找不到 ToolStripItem,因为 ToolStripItem不是 Control

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

假设您拥有 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的重复。

假设您将 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;

一个简单的解决方案是在 foreach循环中迭代 Controls列表:

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

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

child.MouseDown += new MouseEventHandler(dragDown);

使用 菲利普 · 华莱士的相同方法,我们可以这样做:

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

我希望这有帮助! :)

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

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

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

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

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

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

可以在 Form 类中使用 find 函数。如果你想强制转换(标签) ,(文本视图)等,这样你可以使用对象的特殊功能。它将返回 Label 对象。

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

Name : 表单中搜索项的项名

True : 搜索所有孩子的布尔值