如何获取组件对象的名称;不支持.Name属性
本文关键字:不支持 属性 Name 对象 何获取 获取 组件 | 更新日期: 2023-09-27 18:29:10
MenuItem
和ColumnHeader
不是从Control
派生的。在完整的框架中,它们有自己的.Name
属性,但在紧凑的框架中它们没有。在VisualStudio中,表单设计器显示一个(Name)
,当然我可以在代码中使用这个名称访问该对象。但是,如何在运行时将该名称作为字符串获取呢?有没有可能,也许是通过一个返回名称的扩展方法?
背景是我正在创建多语言窗口移动应用程序,为了查找表单上所有项目的文本,我使用控件的名称作为标识符。
这是一个有同样问题的人和他的解决方案,但我不喜欢它,因为在设计器中可视化输入所有名称后,需要在代码中第二次输入所有名称(并在更改时维护它们)。我不得不为许多现有的MenuItems和ColumnHeader做这件事。。。
this.AddMenuToDictionary(this.menuItemOpen, "menuItemOpen");
this.AddMenuToDictionary(this.menuItemExit, "menuItemExit");
如果真的没有比使用这样一个字典更好的解决方案,至少我想在没有硬编码字符串的情况下填充它。我可以在使用反射初始化表单的过程中执行此操作吗?
如果您可以访问表单,而不仅仅是MenuItem
对象本身,那么很容易:
foreach (FieldInfo fi in form.GetType().GetFields(
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
if (fi.FieldType.Name == "MenuItem")
{
var mi = (MenuItem) fi.GetValue(form);
mi.Text = Translate(fi.ReflectedType.Namespace,
fi.ReflectedType.Name + '.' + fi.Name, fi.FieldType.Name, mi.Text);
}
任何改进都非常欢迎,请发表评论,或者创建一个更好的答案。
这也可以更普遍地针对表单中的所有控件进行,或者可能仅针对非源自Control
的组件进行。有了反射,我们甚至不必强制转换为特定类型(如上所述),我们只需查找Text属性的存在并将其翻译即可
但因为我想构建包括子菜单层次结构的标识符,我决定回到Dictionary方法,递归地循环项目(短伪代码):
Dictionary<Component, string> ComponentNames;
foreach (FieldInfo fi in form.GetType().GetFields(
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
if (fi.FieldType.Name == "MenuItem" || fi.FieldType.Name == "ColumnHeader")
ComponentNames.Add((Component) fi.GetValue(form), fi.Name);
void Recurse(Menu menu, string strIdentifier) {
if (ComponentNames.TryGetValue(menu, out strName))
Translate(strIdentifer += '.' + strName, ref strText);
foreach (MenuItem mi in menu.MenuItems) Recurse(mi, strIdentifier);