c#Winform自定义控件-导航菜单

主要用的就是停靠窗体了,(十九)c#Winform自定义控件-停靠窗体,不了解的可以先去看一下

思路:

通过实体对象设置的对齐方式来实现左右对齐,

当鼠标进入一项的时候,判断是否弹出下拉列表,或关闭其他列表

开始

添加一个类用来设置节点信息

复制代码
1 public class NavigationMenuItem
2 {
3 ///
4 /// The icon
5 ///
6 private Image icon;
7 ///
8 /// Gets or sets the icon.
9 ///
10 /// The icon.
11 [Description(“图标,仅顶级节点有效”)]
12 public Image Icon
13 {
14 get { return icon; }
15 set { icon = value; }
16 }
17
18 ///
19 /// The text
20 ///
21 private string text;
22 ///
23 /// Gets or sets the text.
24 ///
25 /// The text.
26
27 [Description(“文本”)]
28 public string Text
29 {
30 get { return text; }
31 set { text = value; }
32 }
33
34 ///
35 /// The show tip
36 ///
37 private bool showTip;
38 ///
39 /// Gets or sets a value indicating whether [show tip].当TipText为空时只显示一个小圆点,否则显示TipText文字
40 ///
41 /// true if [show tip]; otherwise, false.
42 [Description(“是否显示角标,仅顶级节点有效”)]
43 public bool ShowTip
44 {
45 get { return showTip; }
46 set { showTip = value; }
47 }
48
49 ///
50 /// The tip text
51 ///
52 private string tipText;
53 ///
54 /// Gets or sets the tip text
55 ///
56 /// The tip text.
57 [Description(“角标文字,仅顶级节点有效”)]
58 public string TipText
59 {
60 get { return tipText; }
61 set { tipText = value; }
62 }
63 ///
64 /// The items
65 ///
66 private NavigationMenuItem[] items;
67 ///
68 /// Gets or sets the items.
69 ///
70 /// The items.
71 [Description(“子项列表”)]
72 public NavigationMenuItem[] Items
73 {
74 get { return items; }
75 set
76 {
77 items = value;
78 if (value != null)
79 {
80 foreach (var item in value)
81 {
82 item.ParentItem = this;
83 }
84 }
85 }
86 }
87
88 ///
89 /// The anchor right
90 ///
91 private bool anchorRight;
92
93 ///
94 /// Gets or sets a value indicating whether [anchor right].
95 ///
96 /// true if [anchor right]; otherwise, false.
97 [Description(“是否靠右对齐”)]
98 public bool AnchorRight
99 {
100 get { return anchorRight; }
101 set { anchorRight = value; }
102 }
103
104 ///
105 /// The item width
106 ///
107 private int itemWidth = 100;
108
109 ///
110 /// Gets or sets the width of the item.
111 ///
112 /// The width of the item.
113 [Description(“宽度”)]
114 public int ItemWidth
115 {
116 get { return itemWidth; }
117 set { itemWidth = value; }
118 }
119
120 ///
121 /// Gets or sets the data source.
122 ///
123 /// The data source.
124 [Description(“数据源”)]
125 public object DataSource { get; set; }
126 ///
127 /// Gets or sets a value indicating whether this instance has split lint at top.
128 ///
129 /// true if this instance has split lint at top; otherwise, false.
130 [Description(“是否在此项顶部显示一个分割线”)]
131 public bool HasSplitLintAtTop { get; set; }
132
133 ///
134 /// Gets the parent item.
135 ///
136 /// The parent item.
137 [Description(“父节点”)]
138 public NavigationMenuItem ParentItem { get; private set; }
139 }
复制代码
添加一个自定义控件UCNavigationMenu

添加一些属性

复制代码
1 ///
2 /// Occurs when [click itemed].
3 ///
4 [Description(“点击节点事件”), Category(“自定义”)]
5
6 public event EventHandler ClickItemed;
7 ///
8 /// The select item
9 ///
10 private NavigationMenuItem selectItem = null;
11
12 ///
13 /// Gets the select item.
14 ///
15 /// The select item.
16 [Description(“选中的节点”), Category(“自定义”)]
17 public NavigationMenuItem SelectItem
18 {
19 get { return selectItem; }
20 private set { selectItem = value; }
21 }
22
23
24 ///
25 /// The items
26 ///
27 NavigationMenuItem[] items;
28
29 ///
30 /// Gets or sets the items.
31 ///
32 /// The items.
33 [Description(“节点列表”), Category(“自定义”)]
34 public NavigationMenuItem[] Items
35 {
36 get { return items; }
37 set
38 {
39 items = value;
40 ReloadMenu();
41 }
42 }
43
44 ///
45 /// The tip color
46 ///
47 private Color tipColor = Color.FromArgb(255, 87, 34);
48
49 ///
50 /// Gets or sets the color of the tip.
51 ///
52 /// The color of the tip.
53 [Description(“角标颜色”), Category(“自定义”)]
54 public Color TipColor
55 {
56 get { return tipColor; }
57 set { tipColor = value; }
58 }
59
60 ///
61 /// 获取或设置控件的前景色。
62 ///
63 /// The color of the fore.
64 ///
65 ///
66 ///
67 public override System.Drawing.Color ForeColor
68 {
69 get
70 {
71 return base.ForeColor;
72 }
73 set
74 {
75 base.ForeColor = value;
76 foreach (Control c in this.Controls)
77 {
78 c.ForeColor = value;
79 }
80 }
81 }
82 ///
83 /// 获取或设置控件显示的文字的字体。
84 ///
85 /// The font.
86 ///
87 ///
88 ///
89 ///
90 ///
91 ///
92 public override Font Font
93 {
94 get
95 {
96 return base.Font;
97 }
98 set
99 {
100 base.Font = value;
101 foreach (Control c in this.Controls)
102 {
103 c.Font = value;
104 }
105 }
106 }
107
108 ///
109 /// The m LST anchors
110 ///
111 Dictionary<NavigationMenuItem, FrmAnchor> m_lstAnchors = new Dictionary<NavigationMenuItem, FrmAnchor>();
复制代码
重载菜单

复制代码
1 private void ReloadMenu()
2 {
3 try
4 {
5 ControlHelper.FreezeControl(this, true);
6 this.Controls.Clear();
7 if (items != null && items.Length > 0)
8 {
9 foreach (var item in items)
10 {
11 var menu = (NavigationMenuItem)item;
12 Label lbl = new Label();
13 lbl.AutoSize = false;
14 lbl.TextAlign = ContentAlignment.MiddleCenter;
15 lbl.Width = menu.ItemWidth;
16 lbl.Text = menu.Text;
17
18 lbl.Font = Font;
19 lbl.ForeColor = ForeColor;
20
21 lbl.Paint += lbl_Paint;
22 lbl.MouseEnter += lbl_MouseEnter;
23 lbl.Tag = menu;
24 lbl.Click += lbl_Click;
25 if (menu.AnchorRight)
26 {
27 lbl.Dock = DockStyle.Right;
28 }
29 else
30 {
31 lbl.Dock = DockStyle.Left;
32 }
33 this.Controls.Add(lbl);
34
35 lbl.BringToFront();
36 }
37
38
39 }
40 }
41 finally
42 {
43 ControlHelper.FreezeControl(this, false);
44 }
45 }
复制代码
显示下级菜单

复制代码
1 private void ShowMoreMenu(Label lbl)
2 {
3 var menu = (NavigationMenuItem)lbl.Tag;
4 if (CheckShow(menu))
5 {
6 if (menu.Items != null && menu.Items.Length > 0)
7 {
8 Panel panel = new Panel();
9 panel.BackColor = Color.White;
10 panel.Paint += panel_Paint;
11 panel.Padding = new System.Windows.Forms.Padding(1);
12 Size size = GetItemsSize(menu.Items);
13 var height = size.Height * menu.Items.Length + 2;
14 height += menu.Items.Count(p => p.HasSplitLintAtTop);//分割线
15 if (size.Width < lbl.Width)
16 size.Width = lbl.Width;
17 panel.Size = new Size(size.Width, height);
18
19 foreach (var item in menu.Items)
20 {
21 if (item.HasSplitLintAtTop)
22 {
23 UCSplitLine_H line = new UCSplitLine_H();
24 line.Dock = DockStyle.Top;
25 panel.Controls.Add(line);
26 line.BringToFront();
27 }
28 Label _lbl = new Label();
29 _lbl.Font = Font;
30 _lbl.ForeColor = this.BackColor;
31 _lbl.AutoSize = false;
32 _lbl.TextAlign = ContentAlignment.MiddleCenter;
33 _lbl.Height = size.Height;
34 _lbl.Text = item.Text;
35 _lbl.Dock = DockStyle.Top;
36 _lbl.BringToFront();
37 _lbl.Paint += lbl_Paint;
38 _lbl.MouseEnter += lbl_MouseEnter;
39 _lbl.Tag = item;
40 _lbl.Click += lbl_Click;
41 _lbl.Size = new System.Drawing.Size(size.Width, size.Height);
42 panel.Controls.Add(_lbl);
43 _lbl.BringToFront();
44 }
45 Point point = Point.Empty;
46
47 if (menu.ParentItem != null)
48 {
49 Point p = lbl.Parent.PointToScreen(lbl.Location);
50 if (p.X + lbl.Width + panel.Width > Screen.PrimaryScreen.Bounds.Width)
51 {
52 point = new Point(-1 * panel.Width - 2, -1 * lbl.Height);
53 }
54 else
55 {
56 point = new Point(panel.Width + 2, -1 * lbl.Height);
57 }
58 }
59 m_lstAnchors[menu] = new FrmAnchor(lbl, panel, point);
60 m_lstAnchors[menu].FormClosing += UCNavigationMenu_FormClosing;
61 m_lstAnchors[menu].Show();
62 m_lstAnchors[menu].Size = new Size(size.Width, height);
63 }
64 }
65
66 }
复制代码
辅助函数

复制代码
1 ///
2 /// Checks the show.
3 ///
4 /// The menu.
5 /// true if XXXX, false otherwise.
6 private bool CheckShow(NavigationMenuItem menu)
7 {
8 //检查已经打开的节点
9 if (m_lstAnchors.ContainsKey(menu))
10 {
11 CloseList(menu);
12 return false;
13 }
14 if (HasInCacheChild(menu))
15 {
16 if (m_lstAnchors.ContainsKey(menu.ParentItem))
17 {
18 CloseList(menu.ParentItem);
19 return true;
20 }
21 return false;
22 }
23 else
24 {
25 for (int i = 0; i < 1; )
26 {
27 try
28 {
29 foreach (var item in m_lstAnchors)
30 {
31 if (m_lstAnchors[item.Key] != null && !m_lstAnchors[item.Key].IsDisposed)
32 {
33 m_lstAnchors[item.Key].Close();
34 }
35 }
36 }
37 catch
38 {
39 continue;
40 }
41 i++;
42 }
43 m_lstAnchors.Clear();
44 return true;
45 }
46 }
47
48 ///
49 /// Determines whether [has in cache child] [the specified menu].
50 ///
51 /// The menu.
52 /// true if [has in cache child] [the specified menu]; otherwise, false.
53 private bool HasInCacheChild(NavigationMenuItem menu)
54 {
55 foreach (var item in m_lstAnchors)
56 {
57 if (item.Key == menu)
58 {
59 return true;
60 }
61 else
62 {
63 if (item.Key.Items != null)
64 {
65 if (item.Key.Items.Contains(menu))
66 return true;
67 }
68 }
69 }
70 return false;
71 }
72
73 ///
74 /// Closes the list.
75 ///
76 /// The menu.
77 private void CloseList(NavigationMenuItem menu)
78 {
79 if (menu.Items != null)
80 {
81 foreach (var item in menu.Items)
82 {
83 CloseList(item);
84 if (m_lstAnchors.ContainsKey(item))
85 {
86 if (m_lstAnchors[item] != null && !m_lstAnchors[item].IsDisposed)
87 {
88 m_lstAnchors[item].Close();
89 m_lstAnchors[item] = null;
90 m_lstAnchors.Remove(item);
91 }
92 }
93 }
94 }
95 }
复制代码
一些事件

复制代码
1 ///
2 /// Handles the Click event of the lbl control.
3 ///
4 /// The source of the event.
5 /// The instance containing the event data.
6 void lbl_Click(object sender, EventArgs e)
7 {
8 Label lbl = sender as Label;
9 if (lbl.Tag != null)
10 {
11 var menu = (NavigationMenuItem)lbl.Tag;
12 if (menu.Items == null || menu.Items.Length <= 0)
13 {
14 selectItem = menu;
15
16 while (m_lstAnchors.Count > 0)
17 {
18 try
19 {
20 foreach (var item in m_lstAnchors)
21 {
22 item.Value.Close();
23 m_lstAnchors.Remove(item.Key);
24 }
25 }
26 catch { }
27 }
28
29 if (ClickItemed != null)
30 {
31 ClickItemed(this, e);
32 }
33 }
34 else
35 {
36 CloseList(menu);
37 if (m_lstAnchors.ContainsKey(menu))
38 {
39 if (m_lstAnchors[menu] != null && !m_lstAnchors[menu].IsDisposed)
40 {
41 m_lstAnchors[menu].Close();
42 }
43 m_lstAnchors.Remove(menu);
44 }
45 ShowMoreMenu(lbl);
46 }
47 }
48 }
49
50 ///
51 /// Handles the MouseEnter event of the lbl control.
52 ///
53 /// The source of the event.
54 /// The instance containing the event data.
55 void lbl_MouseEnter(object sender, EventArgs e)
56 {
57 Label lbl = sender as Label;
58 ShowMoreMenu(lbl);
59 }
60 ///
61 /// Handles the FormClosing event of the UCNavigationMenu control.
62 ///
63 /// The source of the event.
64 /// The instance containing the event data.
65 void UCNavigationMenu_FormClosing(object sender, FormClosingEventArgs e)
66 {
67 FrmAnchor frm = sender as FrmAnchor;
68 if (m_lstAnchors.ContainsValue(frm))
69 {
70 foreach (var item in m_lstAnchors)
71 {
72 if (item.Value == frm)
73 {
74 m_lstAnchors.Remove(item.Key);
75 return;
76 }
77 }
78 }
79 }
80
81 ///
82 /// Handles the Paint event of the panel control.
83 ///
84 /// The source of the event.
85 /// The instance containing the event data.
86 void panel_Paint(object sender, PaintEventArgs e)
87 {
88 e.Graphics.SetGDIHigh();
89 Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1);
90 var path = rect.CreateRoundedRectanglePath(2);
91 e.Graphics.DrawPath(new Pen(new SolidBrush(LineColors.Light)), path);
92 }
93
94
95
96 ///
97 /// Gets the size of the items.
98 ///
99 /// The items.
100 /// Size.
101 private Size GetItemsSize(NavigationMenuItem[] items)
102 {
103 Size size = Size.Empty;
104 if (items != null && items.Length > 0)
105 {
106 using (var g = this.CreateGraphics())
107 {
108 foreach (NavigationMenuItem item in items)
109 {
110 var s = g.MeasureString(item.Text, Font);
111 if (s.Width + 25 > size.Width)
112 {
113 size.Width = (int)s.Width + 25;
114 }
115 if (s.Height + 10 > size.Height)
116 {
117 size.Height = (int)s.Height + 10;
118 }
119 }
120 }
121 }
122 return size;
123 }
124
125
126 ///
127 /// Handles the Paint event of the lbl control.
128 ///
129 /// The source of the event.
130 /// The instance containing the event data.
131 void lbl_Paint(object sender, PaintEventArgs e)
132 {
133 Label lbl = sender as Label;
134 if (lbl.Tag != null)
135 {
136 var menu = (NavigationMenuItem)lbl.Tag;
137 e.Graphics.SetGDIHigh();
138 if (menu.ParentItem == null)//顶级节点支持图标和角标
139 {
140 if (menu.ShowTip)
141 {
142 if (!string.IsNullOrEmpty(menu.TipText))
143 {
144 var rect = new Rectangle(lbl.Width - 25, lbl.Height / 2 - 10, 20, 20);
145 var path = rect.CreateRoundedRectanglePath(5);
146 e.Graphics.FillPath(new SolidBrush(tipColor), path);
147 e.Graphics.DrawString(menu.TipText, new Font(“微软雅黑”, 8f), new SolidBrush(Color.White), rect, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
148 }
149 else
150 {
151 e.Graphics.FillEllipse(new SolidBrush(tipColor), new Rectangle(lbl.Width - 20, lbl.Height / 2 - 10, 10, 10));
152 }
153 }
154 if (menu.Icon != null)
155 {
156 e.Graphics.DrawImage(menu.Icon, new Rectangle(1, (lbl.Height - 25) / 2, 25, 25), 0, 0, menu.Icon.Width, menu.Icon.Height, GraphicsUnit.Pixel);
157 }
158 }
159 if (menu.ParentItem != null && menu.Items != null && menu.Items.Length > 0)
160 {
161 ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(this.BackColor), new Point(lbl.Width - 11, (lbl.Height - 5) / 2), 5, GraphDirection.Rightward);
162 }
163 }
164 }
复制代码
深圳网站建设www.sz886.com

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值