如何获取不支持.Name属性的组件对象的名称

时间:2014-11-05 13:15:19

标签: c# .net reflection compact-framework

MenuItemColumnHeader不是来自Control。在完整的框架中,它们具有自己的.Name属性,但在紧凑的框架中它们没有。在Visual Studio中,表单设计器显示(Name),当然我可以在代码中使用此名称访问该对象。但是如何在运行时将该名称作为字符串?是否有可能通过一个返回名称的扩展方法?

背景是我正在创建多语言Windows移动应用程序,并且为了查找表单上所有项目的文本,我使用控件的名称作为标识符。

Here是有同样问题的人和他的解决方案,但我不喜欢它,因为他们需要额外努力在代码中再次输入所有名称(并在更改时保留它们)已经在设计师中直观地输入了。我必须为许多现有的MenuItems和ColumnHeaders ......

做这件事
this.AddMenuToDictionary(this.menuItemOpen, "menuItemOpen");
this.AddMenuToDictionary(this.menuItemExit, "menuItemExit");

如果没有比使用这样的字典更好的解决方案,至少我想在没有硬编码字符串的情况下填写它。我可以在使用反射初始化表单时执行此操作吗?

1 个答案:

答案 0 :(得分:1)

如果您可以访问表单,而不仅仅是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);