MenuItem
и ColumnHeader
не являются производными от Control
. В полной структуре они имеют собственное свойство .Name
, но в компактной структуре они этого не делают. В Visual Studio разработчик формы показывает (Name)
и, конечно, я могу получить доступ к этому объекту, используя это имя в коде. Но как я могу получить это имя как строку во время выполнения? Возможно ли это как-то, может быть, методом расширения, который возвращает имя?
Предполагается, что я создаю мобильные приложения с несколькими языковыми окнами, и чтобы найти текст для всех элементов в форме, я использую имя элемента управления как идентификатор.
Вот кто-то с той же проблемой и его решением, но мне это не нравится из-за дополнительных усилий, чтобы вводить все имена во второй раз в коде (а также поддерживать их при изменениях), после того как они уже были введены визуально в конструкторе, Я должен был сделать это для многих существующих MenuItems и ColumnHeaders...
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);