winform 导航栏
搞习惯了B/S的,想把winform的主页面搞成一个类似web网站主页的,首先左侧要有一个导航栏,这个对于winform 来说好像难度有点大了,连直接 拖拽的控件都没有,如果用TreeView的话,那是真的丑,那怎么办呢,只能自己定义一个导航控件了,首先,本人没有艺术细胞,先看看人家框架的导航栏是什么样式的,layui以前用的比较多,那就他了,等一下官网看看盗汗蓝是什么样子的。

上图是官网给的样式,那就照着这个搞一个导航栏,一般导是由图标的,那就在这个基础上加一个图标。这部就妥了吗。
按照上面的做一个,自己要自定义一个导航栏控件,我在网上先搜了一下,有一位大佬的思路不错,在大佬基础上在升华一次。首先现间一个类NavBar继承 FlowLayoutPanel
然后新建一个Model用来存放标题和子标题的。NavBarOption
1 2 3 4 5 6 7 | public class NavBarOption { public string Title { get ; set ; } public object Tag { get ; set ; } public Image image { get ; set ; } public List<NavBarOption> Item { get ; set ; } } |
然后就是自定义这个组件了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | public class NavBar: FlowLayoutPanel { private List<FlowLayoutPanel> childList = new List<FlowLayoutPanel>(); //子类集合 private List<FlowLayoutPanel> parentList = new List<FlowLayoutPanel>(); //父类集合 public event MouseEventHandler ChildItemMouseClick = null ; //子项鼠标事件 public event MouseEventHandler ParentItemMouseClick = null ; //父项鼠标事件 public NavBar() { this .AutoScroll = true ; this .Width = 170; this .BackColor = Color.FromArgb(20, 30, 39); this .Tag = "main" ; //初始化底层容器的标志,容器内的Panel 的 Tag用于存储折叠展开状态 SetScrollBar( this .Handle, 1, 0); //隐藏下、右滚动条 SetScrollBar( this .Handle, 0, 0); } /// <summary> /// 设置子项的字体 /// </summary> [DefaultValue( typeof (Font), "微软雅黑,9pt" )] [Description( "子项的字体" )] public Font ChildItemFont { get { return _childItemFont; } set { _childItemFont = value; } } private Font _childItemFont = new Font( new FontFamily( "微软雅黑" ), 9); /// <summary> /// 设置父项的字体 /// </summary> [DefaultValue( typeof (Font), "微软雅黑,11pt,style=Bold" )] [Description( "父项的字体" )] public Font ParentItemFont { get { return _parentItemFont; } set { _parentItemFont = value; } } private Font _parentItemFont = new Font( new FontFamily( "微软雅黑" ), 11, FontStyle.Bold); /// <summary> /// 设置子项的四边边距 /// </summary> [DefaultValue( typeof (Padding), "10,0,0,0" )] [Description( "设置子项的四边边距" )] public Padding ChiluItemMargin { get { return _childItemMargin; } set { _childItemMargin = value; } } private Padding _childItemMargin = new Padding(0, 0, 0, 0); /// <summary> /// 父节点的背景颜色 /// </summary> [DefaultValue( typeof (Color), "57, 61, 73" )] [Description( "父节点的背景颜色" )] public Color ParentBackColor { get { return _parentBackColor; } set { _parentBackColor = value; } } private Color _parentBackColor = Color.FromArgb(57, 61, 73); /// <summary> /// 子节点的背景颜色 /// </summary> [DefaultValue( typeof (Color), "20, 30, 39" )] [Description( "子节点的背景颜色" )] public Color ChildBackColor { get { return _childBackColor; } set { _childBackColor = value; } } private Color _childBackColor = Color.FromArgb(20, 30, 39); /// <summary> /// 父节点的高度 /// </summary> [DefaultValue( typeof ( int ), "40" )] [Description( "父节点的高度" )] public int ParentHeight { get { return _parentHeight; } set { _parentHeight = value; } } private int _parentHeight = 40; /// <summary> /// 子级节点的高度 /// </summary> [DefaultValue( typeof ( int ), "30" )] [Description( "子节点的高度" )] public int ChildHeight { get { return _childHeight; } set { _childHeight = value; } } private int _childHeight = 30; /// <summary> /// 鼠标悬浮节点的背景颜色 /// </summary> [DefaultValue( typeof (Color), "39, 51, 69" )] [Description( "鼠标悬浮节点的背景颜色" )] public Color MouseHoverBackColor { get { return _mouseHoverBackColor; } set { _mouseHoverBackColor = value; } } private Color _mouseHoverBackColor = Color.FromArgb(39, 51, 69); /// <summary> /// 子节点被选中字体颜色 /// </summary> [DefaultValue( typeof (Color), "28, 134, 238" )] [Description( "子节点被选中字体颜色" )] public Color ChildSelectedForeColor { get { return _childSelectedForeColor; } set { _childSelectedForeColor = value; } } private Color _childSelectedForeColor = Color.FromArgb(255, 255, 255); public void SetNavBar(List<NavBarOption> options) { CreateMenuItemPanels(options, this , _parentHeight, false ); } /// <summary> /// 创建导航栏项 /// </summary> /// <param name="options">项的设置信息</param> /// <param name="parent">项的父容器</param> /// <param name="itemH">项的高度</param> /// <param name="isChildNode">该项是否输入最终子项</param> private void CreateMenuItemPanels(List<NavBarOption> options, FlowLayoutPanel parent, int itemH, bool isChildNode) { if (options == null || options.Count <= 0) return ; foreach (NavBarOption option in options) { FlowLayoutPanel panel = CreatePanel(option, itemH, parent, isChildNode); parent.Controls.Add(panel); if (option.Item != null && option.Item.Count > 0) { CreateMenuItemPanels(option.Item, panel, _childHeight, true ); } } } /// <summary> /// 创建项中的控件 /// </summary> /// <param name="option">项的设置信息</param> /// <param name="itemH">项高度</param> /// <param name="pPanel">项的父容器</param> /// <returns></returns> private FlowLayoutPanel CreatePanel(NavBarOption option, int itemH, FlowLayoutPanel pPanel, bool isChildNode) { NavBar panel = new NavBar(); Label itemL = new Label(); panel.AutoScroll = false ; panel.Height = itemH; if (isChildNode) { panel.BackColor = _childBackColor; panel.Margin = _childItemMargin; childList.Add(panel); } else { panel.BackColor = _parentBackColor; panel.Margin = new Padding(0); parentList.Add(panel); } panel.Width = pPanel.Width; panel.Tag = false ; if (isChildNode) { itemL.Font = _childItemFont; } else { itemL.Font = _parentItemFont; } itemL.Text = option.Title; itemL.TextAlign = ContentAlignment.MiddleCenter; itemL.ImageAlign = ContentAlignment.MiddleLeft; itemL.Image = option.image; //itemL.BackColor = Color.Empty; itemL.ForeColor = Color.White; itemL.Height = panel.Height; itemL.Width = pPanel.Width; itemL.Tag = option; //添加鼠标进入与离开事件 itemL.MouseEnter += ItemL_MouseEnter; itemL.MouseLeave += ItemL_MouseLeave; //如果该节点的子节点不为空,且子节点数大于0 if (option.Item != null && option.Item.Count > 0) { itemL.Paint += ItemL_Paint_Expand; //添加展开与折叠图案绘制 itemL.MouseClick += ItemL_Parent_MouseClick; //展开与折叠事件 if (ParentItemMouseClick != null ) { itemL.MouseClick += ParentItemMouseClick; } } else { itemL.MouseClick += ItemL_Childe_MouseClick; //更改选中状态 if (ChildItemMouseClick != null ) { itemL.MouseClick += ChildItemMouseClick; } } panel.Controls.Add(itemL); return panel; } #region 设置滚动条显示 [DllImport( "user32.dll" , CharSet = CharSet.Auto)] public static extern int ShowScrollBar(IntPtr hWnd, int bar, int show); private class SubWindow : NativeWindow { private int m_Horz = 0; private int m_Show = 0; public SubWindow( int p_Horz, int p_Show) { m_Horz = p_Horz; m_Show = p_Show; } protected override void WndProc( ref Message m_Msg) { ShowScrollBar(m_Msg.HWnd, m_Horz, m_Show); base .WndProc( ref m_Msg); } } /// <summary> /// 设置滚动条是否显示 /// </summary> /// <param name="p_ControlHandle">句柄</param> /// <param name="p_Horz">0横 1列 3全部</param> /// <param name="p_Show">0隐 1显</param> public static void SetScrollBar(IntPtr p_ControlHandle, int p_Horz, int p_Show) { SubWindow _SubWindow = new SubWindow(p_Horz, p_Show); _SubWindow.AssignHandle(p_ControlHandle); } #endregion private void ItemL_Childe_MouseClick( object sender, MouseEventArgs e) { Label label = sender as Label; NavBarOption option = label.Tag as NavBarOption; if (!childList.Contains(label.Parent as FlowLayoutPanel)) return ; //如果子项中不包含该控件,则退出 InitializaAllChildItem(); //初始化所有子节点 label.Font = new Font(_childItemFont.FontFamily, _childItemFont.Size + 1, FontStyle.Bold); label.ForeColor = Color.White; } /// <summary> /// 初始化所有子节点 /// </summary> public void InitializaAllChildItem() { foreach (FlowLayoutPanel item in childList) { Label l = item.Controls[0] as Label; l.Font = _childItemFont; l.ForeColor = Color.White; } } private void ItemL_Parent_MouseClick( object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { Label label = sender as Label; FlowLayoutPanel p = label.Parent as FlowLayoutPanel; if (( bool )p.Tag) //折叠 { p.Height = label.Height; label.Invalidate(); p.Tag = false ; } else //展开 { CollapseAllItem(); p.Height = (p.Controls.Count - 1) * _childHeight + (p.Controls.Count - 1) * (_childItemMargin.Bottom + _childItemMargin.Top) + _parentHeight; label.Invalidate(); p.Tag = true ; } } } /// <summary> /// 折叠所有节点 /// </summary> public void CollapseAllItem() { foreach (FlowLayoutPanel item in parentList) //折叠所有父节点 { item.Height = _parentHeight; foreach (Control itemControl in item.Controls) { if (itemControl is Label) { itemControl.Invalidate(); break ; } } item.Tag = false ; } } private void ItemL_Paint_Expand( object sender, PaintEventArgs e) { Label label = sender as Label; FlowLayoutPanel panel = label.Parent as FlowLayoutPanel; Pen p = new Pen(Color.White, 2); //int startP = 5; //int drawLW =8; int lHeight = label.Height; int lWidth = label.Width; if (( bool )panel.Tag) //折叠 { e.Graphics.DrawLine(p, lWidth * 7 / 9, lHeight * 2 / 5, lWidth * 15 / 18, lHeight * 3 / 5); e.Graphics.DrawLine(p, lWidth * 15 / 18, lHeight * 3 / 5, lWidth * 8 / 9, lHeight * 2 / 5); } else //展开 { e.Graphics.DrawLine(p, lWidth * 15 / 18, lHeight * 3 / 7, lWidth * 8 / 9, lHeight * 4 / 7); e.Graphics.DrawLine(p, lWidth * 8 / 9, lHeight * 4 / 7, lWidth * 15 / 18, lHeight * 5 / 7); } } private void ItemL_MouseLeave( object sender, EventArgs e) { Label label = sender as Label; label.BackColor = Color.Empty; } private void ItemL_MouseEnter( object sender, EventArgs e) { Label label = sender as Label; label.BackColor = _mouseHoverBackColor; } } |
定义完后,我们重新编译一下,会看到工具箱中出现了这个NavBar的组件:
把控件拖拽到窗体上:
然后填充一下数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | public partial class Form1 : Form { public Form1() { InitializeComponent(); CreateNavi(); } private void CreateNavi() { List<NavBarOption> plist = new List<NavBarOption>(); NavBarOption Poption = new NavBarOption(); Poption.Tag = false ; Poption.Title = "父标题1" ; Poption.image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ); Poption.Item = new List<NavBarOption>(); NavBarOption Coption1 = new NavBarOption() { Title = "子标题1" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; NavBarOption Coption2 = new NavBarOption() { Title = "子标题2" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; Poption.Item.Add(Coption1); Poption.Item.Add(Coption2); plist.Add(Poption); NavBarOption Poption1 = new NavBarOption(); Poption1.Tag = false ; Poption1.Title = "父标题2" ; Poption1.image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ); Poption1.Item = new List<NavBarOption>(); NavBarOption Coption3 = new NavBarOption() { Title = "子标题3" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; NavBarOption Coption4 = new NavBarOption() { Title = "子标题4" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; Poption1.Item.Add(Coption3); Poption1.Item.Add(Coption4); plist.Add(Poption1); NavBarOption Poption2 = new NavBarOption(); Poption2.Tag = false ; Poption2.Title = "父标题3" ; Poption2.image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ); Poption2.Item = new List<NavBarOption>(); NavBarOption Coption5 = new NavBarOption() { Title = "子标题5" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; NavBarOption Coption6 = new NavBarOption() { Title = "子标题6" , Tag = true , image = Image.FromFile( @"F:\项目\MES\Mesfrm\MES.Win.UI\Resources\yes.png" ) }; Poption2.Item.Add(Coption5); Poption2.Item.Add(Coption6); plist.Add(Poption2); navBar1.ChildItemMouseClick += navBar1_ChildItemMouseClick; navBar1.SetNavBar(plist); } private void navBar1_ChildItemMouseClick( object sender, MouseEventArgs e) { Label lb = sender as Label; NavBarOption nav = lb.Tag as NavBarOption; MessageBox.Show(nav.Title); } } |
运行一下看一看效果:
这里导航栏就成了,看一看是不是和layui差不多了。
看一下实际项目中使用效果:
.Net Core
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)