从子控件访问父控件元素的最佳方法是什么
本文关键字:控件 最佳 方法 是什么 访问 元素 | 更新日期: 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 事件中。