private void OpenChildForm(Form childForm){ // 检查传入的子窗体是否为空,如果为空则直接返回,避免空引用异常 if (childForm == null) return; // ===== 新增逻辑:避免重复打开同一个子窗体 ===== // 检查当前子窗体是否就是待打开的子窗体,并且该窗体已经在主面板中显示 // 如果是,则只需将其置顶显示即可,避免重复创建和初始化 if (_currentChildForm == childForm && panel_Main.Controls.Contains(childForm)) { // 将已存在的子窗体置于所有控件的最前面显示 childForm.BringToFront(); // 直接返回,不执行后续的创建和初始化操作 return; } // 检查当前是否有已打开的子窗体 if (_currentChildForm != null) { // 关闭当前正在显示的子窗体 // 这会触发子窗体的关闭事件并释放相关资源 _currentChildForm.Close(); // 从主面板的控件集合中移除当前子窗体 // 确保界面控件结构清晰,避免控件堆积 panel_Main.Controls.Remove(_currentChildForm); } // 更新当前子窗体的引用为新的子窗体 // 用于后续的状态管理和判断 _currentChildForm = childForm; // 将子窗体设置为非顶级窗体,使其能嵌入到父容器中 childForm.TopLevel = false; // 移除子窗体的边框样式,使其能够无缝嵌入主面板 childForm.FormBorderStyle = FormBorderStyle.None; // 设置子窗体的停靠方式为填充整个主面板 // 确保子窗体能自动适应主面板的大小变化 childForm.Dock = DockStyle.Fill; // 将子窗体添加到主面板的控件集合中 // 这是将窗体实际显示在界面上的关键步骤 panel_Main.Controls.Add(childForm); // 将子窗体对象存储在面板的Tag属性中 // 这是一个额外的引用,可用于后续通过Tag快速访问当前子窗体 panel_Main.Tag = childForm; // 确保子窗体在多个控件中位于最顶层显示 // 防止被其他控件遮挡 childForm.BringToFront(); // 显示子窗体,使其在界面上可见 childForm.Show();}代码的整体组织
上面的两个方法是实现窗体切换的关键。剩下的就是代码的组织方式。所有的逻辑都写在 FrmMain.cs 中,因为 FrmMain.cs 是整个程序的入口。
程序启动后,执行的就是 Program.cs 中的 Application.Run(new FrmMain());。
FrmMain.cs 中的代码包括窗体切换的方法、各个按钮的 Click 事件,以及 FrmMain 的构造方法(用于初始化界面和组件)。
完整代码已托管在 GitHub,此处仅展示结构:
namespace SCADAPlatform//命名空间 { publicpartialclassFrmMain : Form// 类 { //私有字段 private Button _currentBtn; private Panel _leftBorderBtn; private Form _currentChildForm; //构造方法 public FrmMain() {//详细代码见Github} //窗体切换方法 privatestruct RgbColors {//详细代码见Github} private void ActiveButton(object senderBtn, Color color) {//详细代码见Github} private void OpenChildForm(Form childForm) {//详细代码见Github} private void DisableButton() {//详细代码见Github} //按钮Click事件 private void btn_Dashboard_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_Trend_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_Setting_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_History_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_Alarm_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_Report_Click(object sender, EventArgs e) {//详细代码见Github} private void btn_Account_Click(object sender, EventArgs e) {//详细代码见Github} } }项目整体结构
如下图所示
总结
通过 ActiveButton 和 OpenChildForm 两个方法的配合,我们实现了菜单按钮的视觉反馈与子窗体的动态切换。这种设计模式结构清晰、易于维护,且具备良好的扩展性——新增一个菜单项,只需复制一个按钮事件,传入对应的颜色和窗体类型即可。
更重要的是,该方案充分利用了 WinForm 的控件嵌套和 Dock 布局机制,避免了手动计算位置和大小的繁琐操作,使界面具备良好的自适应能力。对于初学而言,这也是理解事件驱动、对象引用、窗体生命周期等 C# 核心概念的绝佳实践案例。
关键词
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:iLearning爱学习
出处:mp.weixin.qq.com/s/gjgeHWL1dAVeOrmYVjwygw
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!
方便大家交流、资源共享和共同成长
纯技术交流群,需要加入的小伙伴请扫码,并备注【加群】
推荐阅读
觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!