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

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

 

 

 

posted @ 2023-01-01 16:45  代码如风~~~  阅读(1645)  评论(5编辑  收藏  举报