Каков наилучший способ доступа к элементам родительского элемента управления из дочернего элемента управления? - PullRequest
3 голосов
/ 18 августа 2011

У меня есть родительский элемент управления (основная форма) и дочерний элемент управления (пользовательский элемент управления). Дочерний элемент управления имеет некоторый код, который определяет, какие функции может выполнять приложение (например, сохранять файлы, записывать журналы и т. Д.). Мне нужно показать / скрыть, включить / отключить пункты главного меню главной формы в соответствии с функциональностью. Поскольку я не могу просто написать MainMenu.MenuItem1.Visible = false; (главное меню не видно из дочернего элемента управления), я запускаю событие в дочернем элементе управления и обрабатываю это событие в главной форме. Проблема в том, что мне нужно передать, какие элементы меню нужно показать / скрыть. Для этого я создал перечисление, показывающее, что делать с элементом

public enum ItemMode
{
    TRUE, FALSE, NONE
}

Затем я создал мои Eventargs, которые имеют 6 параметров типа ItemMode (есть 6 пунктов меню, которыми мне нужно управлять). Поэтому каждый раз, когда мне нужно показать 1-й элемент, спрятать 2-й и ничего не делать с остальными, я должен написать что-то вроде этого

e = new ItemModeEventArgs(ItemMode.TRUE, ItemMode.FALSE, ItemMode.NONE, ItemMode.NONE, ItemMode.NONE, ItemMode.NONE);
FireMyEvent(e);

Мне кажется, это слишком много кода, и более того, что если мне понадобится управлять 10 объектами в будущем? Затем мне нужно будет переписать все конструкторы, чтобы добавить еще 4 NONE.

Я считаю, что есть лучший способ сделать это, но я просто не могу понять, что это такое.

Ответы [ 5 ]

2 голосов
/ 18 августа 2011

вы можете создать EventArgs, который принимает ItemMode[] или List<ItemMode> или Dictionary<string, ItemMode> для этих элементов (вместо текущих 6 аргументов) - таким образом, вам не нужно много менять при добавлении больше предметов ...

1 голос
/ 18 августа 2011

Цепочка child-> parent может быть полностью изменена. В таком сценарии запросы будут передаваться из основной формы ее дочерним элементам управления.

Элементы управления, участвующие в обработке команд, должны реализовывать специальный интерфейс:

  interface ICommandHandler
  {
        bool CanInvoke(int commandId);
        void InvokeCommand(int commandId);
        bool UpdateCommand(int commandId, MenuItem item);
  }

Преимущество этого подхода заключается в том, что необходимо проходить только активные элементы управления, а не всех детей. Слабое место - метод UpdateCommand (), который можно вызывать из события Application.Idle или таймера.

надеюсь, это поможет

0 голосов
/ 18 августа 2011

Есть действительно много способов сделать это. Самый простой способ, хотя некоторые будут кричать «плохая практика», это просто передать указатель на главное меню при создании элемента управления. Ваш элемент управления будет иметь такой код:

MenuStrip MainMenu;

internal void SetMainMenu(MenuStrip mainMenu)
{
    MainMenu = mainMenu;
}

и при создании элемента управления:

void CreateControl()
{
    MyUserControlType MyControl = new MyUserControlType();
    MyControl.SetMainMenu(mainMenuStrip); //or whatever you called your main menu
}

Это даст вашему ребенку неограниченный доступ к меню основной формы (поэтому технически это плохая практика). Из дочерней формы вы можете получить доступ к подменю по имени, например:

if (MainMenu != null)
{
    ToolStripMenuItem fileMenu = 
        (ToolStripMenuItem)MainMenu.Items["fileToolStripMenuItem"];
    fileMenu.DropDownItems["exportFileToolStripItem"].Visible = false;
}

Если вы создали элемент управления в конструкторе, вы можете добавить вызов SetMainMenu в файл .design или добавить его в событие загрузки формы.

0 голосов
/ 18 августа 2011

Если вы хотите обрабатывать все изменения из пользовательского элемента управления: вы можете унаследовать свой собственный класс пользовательского элемента управления и добавить ссылку на форму / коллекцию пунктов меню, которые вы хотите изменить. Вы передадите эту ссылку его конструктору, и тогда вы сможете легко изменить меню внутри вашего пользовательского элемента управления

Если, с другой стороны, вы хотите управлять этим на основе событий в своей форме, вы можете реализовать свой собственный класс EventArgs, но я бы сделал это следующим образом:


class ItemModeEventArgs
{
    MenuItemClass target;
    EnumType change;
}

Таким образом, в основном для каждого пункта меню возникает отдельное событие. Каждый аргумент события знает о том, какой пункт меню меняется и как он меняется. Конечно, если у вас есть только два состояния для пунктов меню, поле «изменить» является бесполезным. Таким образом, вам не нужно жестко кодировать функции с n параметрами, где n - количество пунктов меню.

0 голосов
/ 18 августа 2011

Ну, я не могу говорить «лучшим» способом, кроме как в особых случаях, поскольку часто есть несколько одинаково хороших способов. Сначала я подумал о создании класса, у которого есть свойство, которому родитель назначает ссылку на его MainMenu, и которое имеет функции для включения / отключения отдельных меню или элементов. В очень простом случае это может быть так же просто, как передача списка строк, таких как "OptionsScreen=enabled" и т. Д., А затем внутри класса, обрабатывающего эти случаи вручную, во что-то более общее, например, передача строк, таких как "mnuToolsOptions=enabled", и затем поиск меню пункт через свойство .Name. Итак, при запуске создайте экземпляр класса вашего обработчика меню, затем сделайте что-то вроде MenuHandlerHelper.MenuToHandle = MainMenuStrip;.

Что касается дочерней стороны, возможно, у вас могут быть классы, обновляющие MainMenu, производные UserObjects, производные от общего созданного вами свойства со свойством public MyMainMenuHandlerHelper MenuHandlerHelper, и установите его в конструкторе родительской формы так, чтобы дочерние элементы управления могут вызывать функцию обновления меню. Или вы можете получить событие, которое только что вернуло List<string>, содержащее все правила, и запустить его, как вы делаете сейчас.

Это очень простая идея, и она не обрабатывает такие вещи, как возможные столкновения, поэтому вы, вероятно, захотите либо сгенерировать исключение (самое простое). Вы также можете захотеть иметь приоритеты правил (легко) или попытаться объединить функции (может быть сложно определить заказы и тому подобное).

Я был бы рад реализовать некоторые примеры моего мышления, если вы можете немного ограничить проблему для меня (желаемая обработка коллизий и т. Д.), И я на самом деле хотел посмотреть, как будет выглядеть какой-то базовый код, и попытаться, возможно, проверить пара идей, так что если они придут к чему-либо, я выложу здесь код и для них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...