从子控件访问父控件元素的最佳方法是什么

本文关键字:控件 最佳 方法 是什么 访问 元素 | 更新日期: 2023-09-27 18:05:50

我有一个父控件(主窗体(和一个子控件(用户控件(。子控件有一些代码,用于确定应用程序可以执行的功能(例如保存文件、写入日志等(。我需要根据功能显示/隐藏,启用/禁用主窗体的主菜单项。由于我不能只写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。

我相信有更好的方法可以做到这一点,但我就是想不通它是什么。

从子控件访问父控件元素的最佳方法是什么

您可以创建一个EventArgs,该为这些项目获取ItemMode[]List<ItemMode>Dictionary<string, ItemMode>(而不是当前的 6 个参数( - 这样您在添加更多项目时不需要做太多更改......

子>父链可以反转。在这种情况下,请求将从主窗体传递到其子控件。

参与命令处理的控件必须实现一个特殊的接口:

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

此方法的优点是,只需遍历活动控件,而不是遍历所有子控件。弱点 - UpdateCommand(( 方法,可以从 Application.Idle 事件或计时器调用。

希望这有帮助

好吧,除非在特定情况下,否则我不能说"最佳"方式,因为通常有几种同样好的方法。不过,我的第一个想法是创建一个类,该类具有父级为其MainMenu分配引用的属性,并且具有启用/禁用单个菜单或项的函数。在一个非常简单的情况下,这可以像传递字符串列表(如"OptionsScreen=enabled"等(,然后在类内部手动处理这些情况一样简单,也可以传递更通用的东西,例如传递字符串(如"mnuToolsOptions=enabled"(,然后通过 .Name 属性查找菜单项。 因此,在启动时,创建菜单处理程序类的实例,然后执行类似 MenuHandlerHelper.MenuToHandle = MainMenuStrip; 的操作。

在子级方面,您可以让更新MainMenu派生的类UserObjects派生自您创建的具有 public MyMainMenuHandlerHelper MenuHandlerHelper 属性的公共类,并在父窗体的构造函数中设置该类,以便子控件可以调用菜单更新函数。或者,您可能有一个事件刚刚传回包含所有规则的List<string>,然后像现在一样触发它。

这是一个非常简单的想法,并且不处理可能的冲突之类的事情,因此您可能希望抛出异常(最简单的(。 您可能还希望具有规则优先级(简单(,或尝试链接功能(可能难以确定顺序等(。

如果您能为我稍微限制问题(所需的碰撞处理等(,我很乐意实现一些我的想法示例,我实际上想看看一些基本代码会是什么样子,并尝试测试一些想法,所以如果这些有什么好处,我也会在这里发布代码。

如果要处理来自用户控件的所有更改:可以继承自己的用户控件类,并添加对希望能够修改的菜单项的窗体/集合的引用。将此引用传递给其构造函数,然后可以轻松地从用户控件内部修改菜单

另一方面,如果您想在表单中基于事件进行管理,则可以实现自己的 EventArgs 类,但我会这样做:


class ItemModeEventArgs
{
    MenuItemClass target;
    EnumType change;
}

所以基本上对于每个菜单项都会引发一个单独的事件。每个事件参数都知道什么项目菜单正在更改以及它是如何变化的。Ofc,如果你的菜单项只有两个状态,"更改"字段有点没用。这样,您就不必使用 n 个参数对函数进行硬编码,其中 n 是菜单项的数量。

确实有很多方法可以做到这一点。 最简单的方法,尽管有些人会大喊"不好的做法",只是在创建控件时传递指向主菜单的指针。 您的控件将具有如下所示的代码:

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 文件中,或将其添加到窗体的 load 事件中。