winform ---无限级导航栏

新建一个用户组件,直接上代码:

    /*
    * 作者:pengyan zhang
    * 邮箱:3073507793@qq.com
    * 网站:https://www.cnblogs.com/zpy1993-09
    * 时间:2024-04-11 17:50
    */
    public partial class CPNavBarComponent : FlowLayoutPanel
    {
        #region Event
        /// <summary>
        /// 委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void NavBarEventHandler(object sender, DataEventArgs e);
        /// <summary>
        /// 开关状态发生改变时引发的事件
        /// </summary>
        public event NavBarEventHandler NavBarEvent;
        #endregion
        private int width { get; set; } = 200;
        [Category("SimpleUI"), Description("导航栏的高度")]
        public int Nav_Height
        {
            get { return NavHeight; }
            set { NavHeight = value;this.Height = value; Invalidate(); }
        }
        private int NavHeight { get; set; } = 600;
        [Category("SimpleUI"), Description("导航栏的的背景颜色"), DefaultValue(typeof(Color), "20, 30, 39")]
        public Color Nav_BackColor
        {
            get { return NavBackColor; }
            set { NavBackColor = value;this.BackColor = value; Invalidate(); }
        }
        private Color NavBackColor { get; set; } = Color.FromArgb(20, 30, 39);
        [Category("SimpleUI"), Description("导航栏每一个子项的高度")]
        public int Nav_BarItemHeight
        {
            get { return NavBarItemHeight; }
            set { NavBarItemHeight = value;  Invalidate(); }
        }
        private int NavBarItemHeight { get; set; } = 50;
        [Category("SimpleUI"), Description("父节点的背景颜色"), DefaultValue(typeof(Color), "57, 61, 73")]
        public Color Nav_ParentBackColor
        {
            get { return ParentBackColor; }
            set { ParentBackColor = value; Invalidate();}
        }
        private Color ParentBackColor { get; set; } = Color.FromArgb(57, 61, 73);
        [Category("SimpleUI"), Description("子节点的背景颜色"), DefaultValue(typeof(Color), "57, 61, 73")]
        public Color Nav_ChildBackClolor
        {
            get { return  ChildBackColor; }
            set { ChildBackColor = value; }
        }
        private Color ChildBackColor { get; set; } = Color.FromArgb(57, 61, 73);
        [Category("SimpleUI"), Description("父项的字体"), DefaultValue(typeof(Color), "255, 255, 255")]
        public Color Nav_ParentFontColor
        {
            get { return ParentFontColor; }
            set { ParentFontColor = value;}
        }
        private Color ParentFontColor { get; set; } = Color.FromArgb(255, 255, 255);
        [Category("SimpleUI"), Description("子项的字体颜色"), DefaultValue(typeof(Color), "255, 255, 255")]
        public Color Nav_ChildFontColor
        {
            get { return ChildFontColor; }
            set { ChildFontColor = value; }
        }
        private Color ChildFontColor { get; set; } = Color.FromArgb(255, 255, 255);
        [Category("SimpleUI"), Description("鼠标悬浮节点的背景颜色"), DefaultValue(typeof(Color), "20, 30, 39")]
        public Color Nav_MouseHoverBackColor
        {
            get { return MouseHoverBackColor; }
            set { MouseHoverBackColor = value; }
        }
        private Color MouseHoverBackColor { get; set; } = Color.FromArgb(20, 30, 39);
        [Category("SimpleUI"), Description("子节点被选中字体颜色"), DefaultValue(typeof(Color), "86, 126, 250")]
        public Color Nav_SelectedForeColor
        {
            get { return SelectedForeColor; }
            set { SelectedForeColor = value; }
        }
        private Color SelectedForeColor = Color.FromArgb(86, 126, 250);
        private FlowLayoutPanel CurrentflowLayoutPanel { get; set; }
        private Label CurrentLabel { get; set; }
        public CPNavBarComponent()
        {
            InitializeComponent();
        }

        public CPNavBarComponent(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            this.AutoScroll = true;
            this.Width = this.width;
            this.BackColor = NavBackColor;
            this.Tag = "main";//初始化底层容器的标志,容器内的Panel 的 Tag用于存储折叠展开状态
            SetScrollBar(this.Handle, 1, 0);//隐藏下、右滚动条
            SetScrollBar(this.Handle, 0, 0);
        }
        protected override void OnResize(EventArgs ea)
        {
            this.Width = 200;
            base.OnResize(ea);
        }
        public void SetBar(List<NavBarOption> options)
        {
            DealNavList(options, 0);
            CreateMenu(options, this);
        }
        private void DealNavList(List<NavBarOption> options,int level)
        {
            if (options.Count > 0)
            {
                options.ForEach(option =>
                {
                    option.Level = level;
                    option.IsCollapse = false;
                    if(option.NavBarItem.Count>0)
                    {
                       option.IsChild = true;
                        DealNavList(option.NavBarItem, level + 1);
                    }
                    else option.IsChild = false;
                });
            }
        }
        public void CreateMenu(List<NavBarOption> options, FlowLayoutPanel pParent)
        {
            if (options == null || options.Count <= 0) return;
            foreach (NavBarOption option in options)
            {
                FlowLayoutPanel navBar = CreateItemMenu(option, pParent);
                pParent.Controls.Add(navBar);
                if (option.NavBarItem!= null && option.NavBarItem.Count > 0)
                {
                    CreateMenu(option.NavBarItem,navBar);
                }
            }
        }
        public FlowLayoutPanel CreateItemMenu(NavBarOption option,FlowLayoutPanel pParent)
        {
            Label barItem = new Label();
            option.FlowContain.AutoScroll = false;
            if (option.IsChild) barItem.Image = Properties.Resources.top;
            option.FlowContain.BackColor = ParentBackColor;
            option.FlowContain.Margin = new Padding(0);
            option.FlowContain.Width =pParent.Width;
            option.FlowContain.Tag = option ;
            if (string.IsNullOrEmpty(option.ImgTitle))
            {
                barItem.Text =  option.Title;
                barItem.TextAlign = ContentAlignment.MiddleLeft;
                barItem.ImageAlign = ContentAlignment.MiddleRight;
            }
            else
            {
                barItem.UseCompatibleTextRendering = true;
                barItem.Font = IconfontHelper.GetFont();
                string str = "";
                for (int i = 0; i < option.Level; i++) str += "  ";
                barItem.Text = str + IconfontHelper.GetIconFont(option.ImgTitle) + "   " + option.Title;
                barItem.TextAlign = ContentAlignment.MiddleLeft;
                barItem.ImageAlign = ContentAlignment.MiddleRight;
            }
           
        
            barItem.Width = pParent.Width;
            barItem.Tag = option;

            //添加鼠标进入与离开事件
            barItem.MouseEnter += ItemL_MouseEnter;
            barItem.MouseLeave += ItemL_MouseLeave;
            //如果该节点的子节点不为空,且子节点数大于0
            if (option.IsChild)
            { 
                barItem.BackColor = ParentBackColor;
                barItem.ForeColor = ParentFontColor;
                barItem.MouseClick += ItemL_Parent_MouseClick;//展开与折叠事件
            }
            else
            {
                barItem.BackColor = ChildBackColor;
                barItem.ForeColor = ChildFontColor;
                barItem.MouseClick += barItem_Childe_MouseClick;//更改选中状态
            }
            option.FlowContain.Height = NavBarItemHeight;
            barItem.Height = option.FlowContain.Height;

            option.FlowContain.Controls.Add(barItem);
            return option.FlowContain;
        }
        private void ItemL_MouseLeave(object? sender, EventArgs e)
        {
            var label = sender as Label;
            var option = label.Tag as NavBarOption;
            if (option.IsChild) label.BackColor = ParentBackColor;
            else label.BackColor = ChildBackColor ;


        }
        private void ItemL_MouseEnter(object? sender, EventArgs e)
        {
            var label=sender as Label;
            label.BackColor = Nav_MouseHoverBackColor ;

            label.Cursor = Cursors.Hand;
        }
        private void barItem_Childe_MouseClick(object? sender, MouseEventArgs e)
        {
            var label=sender as Label;
            var option = label.Tag as NavBarOption;
            if (CurrentLabel == null)
            {
                CurrentLabel = label;
           
                label.ForeColor = SelectedForeColor;
            }
            else
            {
                if (label != CurrentLabel)
                {
                    label.ForeColor = SelectedForeColor;

                    if (option.IsChild) CurrentLabel.ForeColor = ParentFontColor;
                    else CurrentLabel.ForeColor = ChildFontColor;
                    CurrentLabel = label;
                }
            }
          
           if(NavBarEvent!=null) NavBarEvent.Invoke(label, new DataEventArgs(option));

           
        }
        private void CollapseBar(FlowLayoutPanel flow,int height)
        {
            if (flow.Parent == this) return;
            flow.Parent.Height = flow.Parent.Height += height;
            CollapseBar(flow.Parent as FlowLayoutPanel,height);
        }
        private void MergeBar(FlowLayoutPanel flow)
        {
            var option = flow.Tag as NavBarOption;
            MergeChild(option);
            if (option.Level != 0)
            {
                int height = 0;
                GetHeight(option, ref height);
                MergeParent(flow.Parent as FlowLayoutPanel, height);
            }
            InitBar(option);
        }
        private void MergeParent(FlowLayoutPanel flow,int height)
        {
            if (flow == this) return;
            flow.Height = flow.Height - height;
            MergeParent(flow.Parent as FlowLayoutPanel, height);
        }
        private void InitBar(NavBarOption option)
        {
            if (option.AddHeight > 0 && option.IsCollapse == true)
            {
                option.AddHeight = 0;
                option.IsCollapse = false;
                (option.FlowContain.Controls[0] as Label).Image = Properties.Resources.top;
            }
            if (option.IsChild)
             foreach (var item in option.NavBarItem)
              if (item.IsCollapse == true) InitBar(item);
        }
        private void MergeChild(NavBarOption option)
        {
            if (option.AddHeight > 0&&option.IsCollapse==true)
            {
                int barHeight = 0;
                GetHeight(option, ref barHeight);
                option.FlowContain.Height = option.FlowContain.Height - barHeight;
            }
            if (option.IsChild)
            {
                foreach (var item in option.NavBarItem)
                {
                    if (item.IsCollapse == true) MergeChild(item);
                }
            }
        }
        private void GetHeight(NavBarOption option,ref int height)
        {
            if(option.AddHeight > 0 && option.IsCollapse == true)
            {
                height += option.AddHeight;
            }
            if (option.IsChild)
             foreach(var item in option.NavBarItem)
               if(item.IsCollapse == true) GetHeight(item,ref height);
        }
        private void ResetBar(FlowLayoutPanel flow)
        {
            if (CurrentflowLayoutPanel == null) return;
            if (flow == CurrentflowLayoutPanel) return;
           if (flow.Parent == this)
            {
                foreach (FlowLayoutPanel item in this.Controls)
                if (item != flow && (item.Tag as NavBarOption).IsCollapse == true) MergeBar(item);
            } 
            else
            {       
              (flow.Parent.Tag as NavBarOption).NavBarItem.ForEach(
                  m =>{if (m.FlowContain != flow && m.IsCollapse == true) MergeBar(m.FlowContain);});
            }
        }
        private void ItemL_Parent_MouseClick(object? sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Label label = sender as Label;
                
                FlowLayoutPanel flow= label.Parent as FlowLayoutPanel;
                var option=flow.Tag as NavBarOption;
               
                if (option.IsCollapse)//折叠
                {
                    label.Image = Properties.Resources.top;
                     MergeBar(flow);
                    label.Invalidate();
                    option.IsCollapse = false;
                    CurrentflowLayoutPanel = flow;
                }   
                else//展开
                {
                    label.Image = Properties.Resources.bottom;
                    if (CurrentflowLayoutPanel!=flow)ResetBar(flow);
                    flow.Height = flow.Controls.Count * NavBarItemHeight;
                    option.AddHeight = flow.Height - NavBarItemHeight;
                    if (option.Level != 0) CollapseBar(flow, flow.Height- NavBarItemHeight);
                    label.Invalidate();
                    option.IsCollapse=true;
                    CurrentflowLayoutPanel = flow;
                }
            }
        }
        #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
    }
    public class NavBar
    {
        public int Level { get; set; }
        public bool IsChild { get; set; }
        public int AddHeight { get; set; } = 0;
        public bool IsCollapse { get; set; }
        public FlowLayoutPanel FlowContain = new FlowLayoutPanel();
    }
    public class NavBarOption:NavBar
    {
        public string Title { get; set; }
        public string ImgTitle { get; set; }
        public string Path { get; set; }
        public long vmPoiId { get; set; }
        public long tagId { get; set; }
        public string username { get; set; }
        public object Data { get; set; }
        public List<NavBarOption> NavBarItem { get; set; }=new List<NavBarOption>();

        
    }

图标用的是字体图标,如何引入字体图标,自己查找:

 public class IconfontHelper
    {
        private static Dictionary<string, string> _icons = new Dictionary<string, string>()
        {
            { "sync","e697" },        { "todo","e698" },          { "toggle-left","e699" },     { "toggle-right","e69a" },
            {"top","e69b"},           {"unexecuted","e69c"},      {"upload","e69d"},            {"user-avatar","e69e"}, 
            {"wtgkcl","e69f"},        {"wtcsbg","e6a0"},          {"ywbl","e6a2"},              {"xfaq","e6a1"}, 
            {"yxgl","e6a3"},          {"zgcscx","e6a4"},          {"zgcszx","e6a6"},            {"accessory","e61f"},
            {"zhcx","e6a7"},          {"ztjx","e6a8"},            {"accept-check","e61e"},      {"add","e620"},
            {"appraise","e621"},      {"apply","e622"},           {"ajpt-out","e623"},          {"ajpt","e624"},
            {"aqgl","e625"},          {"back","e626"},            {"batch-import","e627"},      {"bookmark","e628"}, 
            {"bottom","e629"},        {"chart","e62a"},           {"circle-return","e62b"},     {"close","e62c"}, 
            {"close-popup","e62d"},   {"copy","e62e"},            {"clean-up","e630"},          {"create","e631"},
            {"cut","e632"},           {"date","e633"},            {"delete","e634"},            {"current-team","e635"},
            {"delay","e636"},         {"department","e637"},      {"detailed-view","e638"},     {"distribute","e639"},
            {"dmp","e63a"},           {"double-left","e63b"},     {"double-right","e63c"},      {"download","e63d"}, 
            {"edit","e63e"},          {"exchange","e63f"},        {"empower","e640"},           {"enable","e641"}, 
            {"execute","e642"},       {"export","e643"},          {"ilter","e644"},             {"finish","e645"}, 
            {"follow","e646"},        {"eye","e647"},             {"forbidden","e648"},         {"full-screen","e649"},
            {"grid_","e64a"},         {"group","e64b"},           {"grid","e64c"},              {"hand-take-over","e64d"},
            {"help","e64e"},          {"hide","e64f"},            {"hn-logo","e650"},           {"import","e651"}, 
            {"insert-before","e653"}, {"invalid","e654"},         {"jcjhbz","e655"},            {"jcjhcx","e656"},
            {"jcjhfk","e657"},        {"jcjhxd","e658"},          {"jcwtcj","e659"},            {"jcjhxg","e65a"}, 
            {"jcwtxg","e65b"},        {"cwtcx","e65c"},           {"jcwtys","e65d"},            {"jcjhjsfj","e65e"},
            {"jsjd","e65f"},          {"insert-after","e652"},    {"jxgl","e660"},              {"left","e661"}, 
            {"line-chart","e662"},    {"logout","e663"},          {"list-view","e664"},         {"lose-effect","e665"},
            {"mobile-phone","e666"},  {"message-view","e667"},    {"more","e668"},              {"move-up","e669"}, 
            {"move-down","e66a"},     {"normal-screen","e66b"},   {"notice","e66c"},            {"organization","e66d"},
            {"pass","e66e"},          {"position","e66f"},        {"personal","e670"},          {"print","e671"},
            {"produce","e672"},       {"produce-card","e673"},    {"publish","e674"},           {"quote","e675"}, 
            {"query","e676"},         {"refresh","e677"},         {"recovery","e678"},          {"register","e679"},
            {"reject","e67a"},        {"report","e67b"},          {"reset","e67c"},             {"return","e67d"},
            {"right","e67e"},         {"save","e67f"},            {"review","e680"},            {"revoke","e681"},
            {"safety-measure","e682"},{"save-as","e683"},         {"scwz","e684"},              {"search","e685"}, 
            {"scxm","e686"},          {"sign-in","e687"},         {"setting","e688"},           {"sjgl","e689"}, 
            {"sjgl-out","e68a"},      {"solid-message","e68b"},   {"solid-bell","e68c"},        {"solid-letter","e68d"},
            {"solid-notice","e68e"},  {"solid-star","e68f"},      {"star","e690"},              {"start","e691"},
            {"stop","e692"},          {"submit","e693"},          {"stop-use","e694"},          {"subtract","e695"}, 
            {"sure","e696"}






        };
        public static Font GetFont()
        {
            return new System.Drawing.Font(IconfontHelper.PFCC.Families[0], 10);

        }
        public static string GetIconFont(string iconName)
        {
            string outstr = "\\u" + _icons[iconName];
            char iconChar = (char)int.Parse(outstr.Substring(2), NumberStyles.HexNumber);
            return iconChar.ToString();
        }
        public static System.Drawing.Text.PrivateFontCollection PFCC
        {
            get
            {
                return pfcc ?? LoadFont();
            }
        }
        //提供一个字体系列集合,该集合是基于客户端应用程序提供的字体文件生成的。
        private static System.Drawing.Text.PrivateFontCollection pfcc;
        private static System.Drawing.Text.PrivateFontCollection LoadFont()
        {
            pfcc = new System.Drawing.Text.PrivateFontCollection();
            byte[] fontData = Properties.Resources.iconfont;//添加到资源里面的字体库文件

            unsafe
            {
                fixed (byte* pFontData = fontData)
                {
                    pfcc.AddMemoryFont((IntPtr)pFontData, fontData.Length);
                }
            }
            return pfcc;
        }
    }
 private void Init()
        {
            //cpNavBarComponent1.NavBarEvent += NavBar_Click;
            List<NavBarOption> options = new List<NavBarOption>();
            NavBarOption nav1 = new NavBarOption();
            nav1.Title = "系统设置";
            nav1.IsChild = true;
            nav1.ImgTitle = "sync";
            nav1.NavBarItem.Add(new NavBarOption() { Title = "日志列表", IsChild = false, ImgTitle = "sync" });
            nav1.NavBarItem.Add(new NavBarOption() { Title = "日志列表1", IsChild = false, ImgTitle = "sync" });

            NavBarOption nav1_1 = new NavBarOption();
            nav1_1.Title = "日志列表1-1";
            nav1_1.ImgTitle = "sync";
            nav1_1.IsChild = true;
            nav1.NavBarItem.Add(nav1_1);

            NavBarOption nav1_2 = new NavBarOption();
            nav1_2.Title = "日志列表1-2";
            nav1_2.IsChild = false;
            nav1_2.ImgTitle = "sync";
            nav1.NavBarItem.Add(nav1_2);
            NavBarOption nav1_2_1 = new NavBarOption();
            nav1_2_1.Title = "日志列表1-2";
            nav1_2_1.IsChild = false;
            nav1_2_1.ImgTitle = "sync";
            nav1_2.NavBarItem.Add(nav1_2_1);

            NavBarOption nav1_1_1 = new NavBarOption();
            nav1_1_1.Title = "日志列表1-1-1";
            nav1_1_1.ImgTitle = "sync";
            nav1_1_1.IsChild = false;
            nav1_1.NavBarItem.Add(nav1_1_1);
            NavBarOption nav1_1_1_1 = new NavBarOption();
            nav1_1_1_1.Title = "324242";
            nav1_1_1_1.IsChild = false;
            nav1_1_1_1.ImgTitle = "sync";
            nav1_1_1.NavBarItem.Add(nav1_1_1_1);

            NavBarOption nav1_1_1_2 = new NavBarOption();
            nav1_1_1_2.Title = "324242";
            nav1_1_1_2.IsChild = false;
            nav1_1_1_2.ImgTitle = "sync";
            nav1_1_1.NavBarItem.Add(nav1_1_1_2);
            NavBarOption nav1_1_2_2 = new NavBarOption();
            nav1_1_2_2.Title = "324242";
            nav1_1_2_2.IsChild = false;
            nav1_1_2_2.ImgTitle = "sync";
            nav1_2_1.NavBarItem.Add(nav1_1_2_2);
            NavBarOption nav2 = new NavBarOption();
            nav2.Title = "用户管理";
            nav2.IsChild = true;
            nav2.ImgTitle = "sync";
            nav2.NavBarItem.Add(new NavBarOption() { Title = "日志列表", IsChild = false, ImgTitle = "sync" });
            nav2.NavBarItem.Add(new NavBarOption() { Title = "日志列表1", IsChild = false, ImgTitle = "sync" });


            NavBarOption nav3 = new NavBarOption();
            nav3.Title = "首页";
            nav3.IsChild = true;
            nav3.ImgTitle = "sync";
            options.Add(nav3);
            options.Add(nav1);
            options.Add(nav2);

            cpNavBarComponent1.SetBar(options);


        }

效果图:

 

posted @ 2024-07-22 15:35  代码如风~~~  阅读(31)  评论(0编辑  收藏  举报