『7x24小时有问必答』

前言

本文将详细解析一个常见但实用的 WinForm 界面功能:点击左侧菜单按钮,动态切换右侧主区域显示的子窗体,并同步更新按钮的视觉状态。这种模式广泛应用于管理后台、SCADA 系统、配置工具等桌面应用中,是构建专业级用户界面的基础。

项目效果

1.gif
2.png
从这里开始,要涉及到一些基本概念,比如事件、类、继承、构造方法、new关键字……这些概念其实很容易找到答案,随便打开一个AI工具,输入诸如"请用通俗的语言给我解释一下C语言中事件、类的概念"诸如此类的Prompt,它的解释非常清楚易懂,或者将代码直接粘贴给它,让它生成详细的注释。写代码是AI的强项,所以要善用。

两个核心方法

第一个方法:ActiveButton

3.png
这里的  senderBtn  代表触发这个方法的 Click 事件是哪个 Button 的。如果是  btn_Dashboard  的 Click 事件触发的,那  senderBtn  就是  btn_Dashboard  对象,_currentBtn = (Button)senderBtn;  中的  _currentBtn  就是  btn_Dashboard。之后的代码就没有难度了,无非是设置 Button 的各种属性。
其中,_leftBorderBtn  就是点击后出现在按钮左侧的那个矩形竖条,通过动态设置其  Location.Y  与当前按钮对齐,实现"跟随高亮"的效果。

第二个方法:OpenChildForm

4.png
以下是 AI 为该方法生成的详细注释,清晰易懂:
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}   

      }   

}

项目整体结构

如下图所示
5.png

总结

通过  ActiveButton  和  OpenChildForm  两个方法的配合,我们实现了菜单按钮的视觉反馈与子窗体的动态切换。这种设计模式结构清晰、易于维护,且具备良好的扩展性——新增一个菜单项,只需复制一个按钮事件,传入对应的颜色和窗体类型即可。
更重要的是,该方案充分利用了 WinForm 的控件嵌套和 Dock 布局机制,避免了手动计算位置和大小的繁琐操作,使界面具备良好的自适应能力。对于初学而言,这也是理解事件驱动、对象引用、窗体生命周期等 C# 核心概念的绝佳实践案例。

关键词

最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠]  社区,与其他热爱技术的同行一起交流心得,共同成长!
作者:iLearning爱学习
出处:mp.weixin.qq.com/s/gjgeHWL1dAVeOrmYVjwygw
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!

END

方便大家交流、资源共享和共同成长
纯技术交流群,需要加入的小伙伴请扫码,并备注加群

推荐阅读

觉得有收获?不妨分享让更多人受益
关注「DotNet技术匠」,共同提升技术实力

收藏
点赞
分享
在看

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码