如何在Visual Studio窗体应用中跨窗体控制菜单的启用与禁用?
解决WinForms主窗体菜单随子窗体状态启用/禁用的问题
错误原因分析
你遇到的An object reference is required...错误,是因为直接通过类名TelaPrincipal.M_Selecao访问菜单控件——菜单是主窗体实例的成员,不是静态成员,必须通过主窗体的实际对象实例才能访问。另外,直接修改TelaPrincipal.Designer.cs里的控件访问修饰符不可取,因为设计器会自动覆盖该文件的内容,你的修改会丢失。
下面提供两种可靠的解决方案:
方案一:子窗体端处理(需传递主窗体实例)
1. 封装主窗体菜单控件
在TelaPrincipal.cs中添加一个公共属性,封装菜单控件,避免直接暴露控件且不会被设计器覆盖:
public System.Windows.Forms.ToolStripMenuItem SelecaoMenu { get { return M_Selecao; } }
2. 打开子窗体时传递主窗体实例
在主窗体打开Expenses子窗体的代码中,将当前主窗体实例设为子窗体的Owner:
private void AbrirExpensesToolStripMenuItem_Click(object sender, EventArgs e) { ExpensesForm expensesForm = new ExpensesForm(); // 传递主窗体实例给子窗体 expensesForm.Owner = this; expensesForm.Show(); // 子窗体打开时启用菜单 M_Selecao.Enabled = true; }
3. 子窗体关闭时禁用菜单
在Expenses子窗体的FormClosed事件中,通过Owner获取主窗体实例并操作菜单:
private void ExpensesForm_FormClosed(object sender, FormClosedEventArgs e) { TelaPrincipal mainForm = this.Owner as TelaPrincipal; if (mainForm != null) { mainForm.SelecaoMenu.Enabled = false; } }
方案二:主窗体端处理(推荐,解耦性更好)
这种方法不需要修改子窗体代码,所有逻辑都在主窗体中实现,避免子窗体依赖主窗体细节:
1. 订阅子窗体关闭事件
在主窗体打开Expenses子窗体时,订阅其FormClosed事件:
private void AbrirExpensesToolStripMenuItem_Click(object sender, EventArgs e) { ExpensesForm expensesForm = new ExpensesForm(); // 订阅子窗体关闭事件 expensesForm.FormClosed += ExpensesForm_FormClosed; expensesForm.Show(); // 启用菜单 M_Selecao.Enabled = true; }
2. 实现关闭事件处理逻辑
在主窗体中添加事件处理方法,子窗体关闭时禁用菜单,并取消订阅事件避免内存泄漏:
private void ExpensesForm_FormClosed(object sender, FormClosedEventArgs e) { M_Selecao.Enabled = false; // 取消订阅事件,防止内存泄漏 ExpensesForm closedForm = sender as ExpensesForm; if (closedForm != null) { closedForm.FormClosed -= ExpensesForm_FormClosed; } }
内容的提问来源于stack exchange,提问作者Ismael
相关产品推荐
相关产品推荐

