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

浙公网安备 33010602011771号