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); }
效果图:
.Net Core