2011-08-18 75 views
3

我有一个父控件(主窗体)和一个子控件(用户控件)。子控件有一些代码,它决定了应用程序可以执行哪些功能(例如保存文件,写入日志等)。我需要显示/隐藏,根据功能启用/禁用主窗体的主菜单项。因为我不能写MainMenu.MenuItem1.Visible = false;(主菜单在子控件中不可见),所以我在子控件中触发一个事件并在主窗体上处理这个事件。问题是我需要传递哪些菜单元素需要显示/隐藏。要做到这一点,我创建了一个枚举,展示了与从子控件访问父控件元素的最佳方式是什么?

public enum ItemMode 
{ 
    TRUE, FALSE, NONE 
} 

然后我创造了我的EventArgs具有ItemMode类型的6个参数的项目做(有我需要管理6菜单项)。所以,任何时候,我需要显示的第一个项目,隐藏第二,什么也不做,其余的我必须写这样的事情

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

这似乎是太多的代码给我,更重要的是,如果我需要什么今后要管理10个项目?然后,我将不得不重写所有构造函数,以添加4个NONE。

我相信有这样做的更好的办法,但我只是无法弄清楚它是什么。

+1

+1对于一个有趣的问题,用代码给出足够的细节来了解当前的处理方式 – shelleybutterfly

回答

2

您可以创建一个EventArgs这需要一个ItemMode[]List<ItemMode>或这些项目(而不是现在的6个参数)一个Dictionary<string, ItemMode> - 这样增加更多的物品,当你不需要太大的变化...

+0

'Dictionary'看起来很有前途,我想我会试试看。然而,我想,“List”并不适合我,因为我需要知道显示/隐藏哪个项目,并且如果存在List中的一个项目我怎么知道它是用于哪个元素的。 –

+0

这就是为什么我在答案中包含'Dictionary' ...你甚至可以使用'Dictionary '直接引用相应的控件... – Yahia

1

链式child-> parent可以颠倒过来。在这种情况下,请求将从mainform传递给它的子控件。

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

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

这种方法的优点是只主动控制必须经过,不是所有的孩子们。 弱点 - UpdateCommand()方法,可以从Application.Idle事件或计时器中调用。

希望这有助于

+0

+1另一个好的模式是熟悉。总的来说,我想避免轮询使用,但还有其他方法。例如,为主窗体提供了另一个接口,比如'interface IUpdatableCommandForm',它具有类似'void RegisterHandler(ICommandHandler处理程序,bool enable)'的特性,以允许孩子将其可用性推送给父级。或者在另一个方向上,像'void RegisterReadyCallback(Action callback)一样,在'ICommandHandler'上使用回调注册方法;'孩子可以用来通知父母它的身份以及它是否处于活动状态。 :) – shelleybutterfly

0

好了,我不能为“最好”的方式说话,除非除非在特殊情况下,因为经常有一些同样好的方式。然而,我的第一个想法是创建一个父类指定其MainMenu引用的属性的类,该类具有启用/禁用单个菜单或项目的功能。在非常简单的情况下,这可能是因为通过字符串列表像"OptionsScreen=enabled"等一样简单,然后里面的类手工处理的情况下,更多的东西一般喜欢通过.Name传递字符串,如"mnuToolsOptions=enabled",然后找到菜单项属性。因此,在启动时,创建菜单处理程序类的实例,然后执行类似MenuHandlerHelper.MenuToHandle = MainMenuStrip;的操作。

在孩子身边,也许你可以有你的类,更新MainMenu衍生UserObjects,从常见的一种派生所创建具有public MyMainMenuHandlerHelper MenuHandlerHelper属性,并设置在父窗体的构造函数,以便子控件可以打电话菜单更新功能。或者,您可以参加一个包含所有规则的List<string>事件,然后按照您现在的操作进行操作。

这是一个非常简单的想法,并没有处理可能的冲突事件,所以你可能要么抛出异常(最简单)。您可能还想要规则优先级(简单),或尝试链接功能(可能很难确定订单等)。

如果你能限制我的问题(想要的碰撞处理等),我会很乐意实现我的想法的一些例子,而且我真的想看看一些基本代码是什么样子,并尝试或许测试一些想法,所以如果这些想法出现的话,我也会在这里发布代码。

0

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

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


class ItemModeEventArgs 
{ 
    MenuItemClass target; 
    EnumType change; 
} 

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

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 
} 

这会给你的孩子形式不限访问MainForm的菜单(这就是为什么它在技术上是一个坏的实践)。从孩子形成可以按名称访问子菜单,例如:

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

如果你创建了设计师的控制,那么你可以添加SetMainMenu呼叫进入。设计文件,或在窗体的负载添加它事件。

相关问题