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差不多了。

看一下实际项目中使用效果:

 

 

 

posted @   代码如风~~~  阅读(1823)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示