winform 导航栏
搞习惯了B/S的,想把winform的主页面搞成一个类似web网站主页的,首先左侧要有一个导航栏,这个对于winform 来说好像难度有点大了,连直接 拖拽的控件都没有,如果用TreeView的话,那是真的丑,那怎么办呢,只能自己定义一个导航控件了,首先,本人没有艺术细胞,先看看人家框架的导航栏是什么样式的,layui以前用的比较多,那就他了,等一下官网看看盗汗蓝是什么样子的。
上图是官网给的样式,那就照着这个搞一个导航栏,一般导是由图标的,那就在这个基础上加一个图标。这部就妥了吗。
按照上面的做一个,自己要自定义一个导航栏控件,我在网上先搜了一下,有一位大佬的思路不错,在大佬基础上在升华一次。首先现间一个类NavBar继承 FlowLayoutPanel
然后新建一个Model用来存放标题和子标题的。NavBarOption
public class NavBarOption { public string Title { get; set; } public object Tag { get; set; } public Image image { get; set; } public List<NavBarOption> Item { get; set; } }
然后就是自定义这个组件了:
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的组件:
把控件拖拽到窗体上:
然后填充一下数据:
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