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

时间:2011-08-18 05:34:51

标签: c# winforms user-controls

我有一个父控件(主窗体)和一个子控件(用户控件)。子控件有一些代码,用于确定应用程序可以执行的功能(例如保存文件,写日志等)。我需要根据功能显示/隐藏,启用/禁用主窗体的主菜单项。因为我不能只写MainMenu.MenuItem1.Visible = false;(主菜单在子控件中不可见),我在子控件中触发一个事件并在主窗体上处理此事件。问题是我需要传递菜单中需要显示/隐藏的元素。为此,我创建了一个枚举,显示如何处理项目

public enum ItemMode
{
    TRUE, FALSE, NONE
}

然后我创建了我的eventargs,它有6个ItemMode类型的参数(我需要管理6个菜单项)。因此,每当我需要显示第一项,隐藏第二项并且不做任何其他事情我必须写这样的东西

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

这对我来说似乎太多代码了,更重要的是,如果我将来需要管理10个项目怎么办?然后我将重写所有构造函数只是为了增加4个NONE。

我相信有更好的方法可以做到这一点,但我无法弄清楚它是什么。

5 个答案:

答案 0 :(得分:2)

您可以创建一个EventArgs,其中ItemMode[]List<ItemMode>Dictionary<string, ItemMode>代表这些项目(而不是当前的6个参数) - 这样你就不会添加更多项目时需要进行更改...

答案 1 :(得分:1)

链子 - >父母可以颠倒。在这种情况下,请求将从mainform传递到其子控件。

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

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

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

希望这会有所帮助

答案 2 :(得分:0)

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

在子级方面,您可能会让您的类更新MainMenu派生UserObjects,该类派生自您创建的具有public MyMainMenuHandlerHelper MenuHandlerHelper属性的公共属性,并设置为在您的父窗体的构造函数中,所以子控件可以调用菜单更新功能。或者,您可以发送一个事件,该事件仅传回包含所有规则的List<string>,并按照您现在正在执行的操作进行解雇。

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

我很乐意实现我思考的一些例子,如果你可以为我稍微约束问题(希望碰撞处理等),我实际上想看看一些基本代码会是什么样子并尝试测试一些想法,所以如果有任何想法,我会在这里发布代码。

答案 3 :(得分:0)

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

另一方面,如果您希望在表单中以事件为基础管理它,您可以实现自己的EventArgs类,但我会这样做:


class ItemModeEventArgs
{
    MenuItemClass target;
    EnumType change;
}

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

答案 4 :(得分:0)

真的有很多方法可以做到。最简单的方法,虽然有人会喊出“不好的做法”,但是在创建控件时只需将指针传递给主菜单。你的控件会有这样的代码:

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