(七十九)c#Winform自定义控件-导航菜单

前提

入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。

GitHub:https://github.com/kwwwvagaa/NetWinformControl

码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git

如果觉得写的还行,请点个 star 支持一下吧

欢迎前来交流探讨: 企鹅群568015492 

来都来了,点个【推荐】再走吧,谢谢

NuGet

Install-Package HZH_Controls

目录

https://www.cnblogs.com/bfyx/p/11364884.html

用处及效果

准备工作

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

思路:

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

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

开始

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

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

添加一个自定义控件UCNavigationMenu

添加一些属性

  1 /// <summary>
  2         /// Occurs when [click itemed].
  3         /// </summary>
  4         [Description("点击节点事件"), Category("自定义")]
  5
  6         public event EventHandler ClickItemed;
  7         /// <summary>
  8         /// The select item
  9         /// </summary>
 10         private NavigationMenuItem selectItem = null;
 11
 12         /// <summary>
 13         /// Gets the select item.
 14         /// </summary>
 15         /// <value>The select item.</value>
 16         [Description("选中的节点"), Category("自定义")]
 17         public NavigationMenuItem SelectItem
 18         {
 19             get { return selectItem; }
 20             private set { selectItem = value; }
 21         }
 22
 23
 24         /// <summary>
 25         /// The items
 26         /// </summary>
 27         NavigationMenuItem[] items;
 28
 29         /// <summary>
 30         /// Gets or sets the items.
 31         /// </summary>
 32         /// <value>The items.</value>
 33         [Description("节点列表"), Category("自定义")]
 34         public NavigationMenuItem[] Items
 35         {
 36             get { return items; }
 37             set
 38             {
 39                 items = value;
 40                 ReloadMenu();
 41             }
 42         }
 43
 44         /// <summary>
 45         /// The tip color
 46         /// </summary>
 47         private Color tipColor = Color.FromArgb(255, 87, 34);
 48
 49         /// <summary>
 50         /// Gets or sets the color of the tip.
 51         /// </summary>
 52         /// <value>The color of the tip.</value>
 53         [Description("角标颜色"), Category("自定义")]
 54         public Color TipColor
 55         {
 56             get { return tipColor; }
 57             set { tipColor = value; }
 58         }
 59
 60         /// <summary>
 61         /// 获取或设置控件的前景色。
 62         /// </summary>
 63         /// <value>The color of the fore.</value>
 64         /// <PermissionSet>
 65         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 66         /// </PermissionSet>
 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         /// <summary>
 83         /// 获取或设置控件显示的文字的字体。
 84         /// </summary>
 85         /// <value>The font.</value>
 86         /// <PermissionSet>
 87         ///   <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 88         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 89         ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
 90         ///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
 91         /// </PermissionSet>
 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         /// <summary>
109         /// The m LST anchors
110         /// </summary>
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   /// <summary>
 2         /// Checks the show.
 3         /// </summary>
 4         /// <param name="menu">The menu.</param>
 5         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
 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         /// <summary>
49         /// Determines whether [has in cache child] [the specified menu].
50         /// </summary>
51         /// <param name="menu">The menu.</param>
52         /// <returns><c>true</c> if [has in cache child] [the specified menu]; otherwise, <c>false</c>.</returns>
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         /// <summary>
74         /// Closes the list.
75         /// </summary>
76         /// <param name="menu">The menu.</param>
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 /// <summary>
  2         /// Handles the Click event of the lbl control.
  3         /// </summary>
  4         /// <param name="sender">The source of the event.</param>
  5         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
  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         /// <summary>
 51         /// Handles the MouseEnter event of the lbl control.
 52         /// </summary>
 53         /// <param name="sender">The source of the event.</param>
 54         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
 55         void lbl_MouseEnter(object sender, EventArgs e)
 56         {
 57             Label lbl = sender as Label;
 58             ShowMoreMenu(lbl);
 59         }
 60 /// <summary>
 61         /// Handles the FormClosing event of the UCNavigationMenu control.
 62         /// </summary>
 63         /// <param name="sender">The source of the event.</param>
 64         /// <param name="e">The <see cref="FormClosingEventArgs"/> instance containing the event data.</param>
 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         /// <summary>
 82         /// Handles the Paint event of the panel control.
 83         /// </summary>
 84         /// <param name="sender">The source of the event.</param>
 85         /// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
 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         /// <summary>
 97         /// Gets the size of the items.
 98         /// </summary>
 99         /// <param name="items">The items.</param>
100         /// <returns>Size.</returns>
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         /// <summary>
127         /// Handles the Paint event of the lbl control.
128         /// </summary>
129         /// <param name="sender">The source of the event.</param>
130         /// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
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         }

完整代码

  1 // ***********************************************************************
  2 // Assembly         : HZH_Controls
  3 // Created          : 2019-10-08
  4 //
  5 // ***********************************************************************
  6 // <copyright file="UCNavigationMenu.cs">
  7 //     Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:[email protected]
  8 // </copyright>
  9 //
 10 // Blog: https://www.cnblogs.com/bfyx
 11 // GitHub:https://github.com/kwwwvagaa/NetWinformControl
 12 // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
 13 //
 14 // If you use this code, please keep this note.
 15 // ***********************************************************************
 16 using System;
 17 using System.Collections.Generic;
 18 using System.ComponentModel;
 19 using System.Drawing;
 20 using System.Data;
 21 using System.Linq;
 22 using System.Text;
 23 using System.Windows.Forms;
 24 using HZH_Controls.Forms;
 25
 26 namespace HZH_Controls.Controls
 27 {
 28     /// <summary>
 29     /// Class UCNavigationMenu.
 30     /// Implements the <see cref="System.Windows.Forms.UserControl" />
 31     /// </summary>
 32     /// <seealso cref="System.Windows.Forms.UserControl" />
 33     [DefaultEvent("ClickItemed")]
 34     public partial class UCNavigationMenu : UserControl
 35     {
 36         /// <summary>
 37         /// Occurs when [click itemed].
 38         /// </summary>
 39         [Description("点击节点事件"), Category("自定义")]
 40
 41         public event EventHandler ClickItemed;
 42         /// <summary>
 43         /// The select item
 44         /// </summary>
 45         private NavigationMenuItem selectItem = null;
 46
 47         /// <summary>
 48         /// Gets the select item.
 49         /// </summary>
 50         /// <value>The select item.</value>
 51         [Description("选中的节点"), Category("自定义")]
 52         public NavigationMenuItem SelectItem
 53         {
 54             get { return selectItem; }
 55             private set { selectItem = value; }
 56         }
 57
 58
 59         /// <summary>
 60         /// The items
 61         /// </summary>
 62         NavigationMenuItem[] items;
 63
 64         /// <summary>
 65         /// Gets or sets the items.
 66         /// </summary>
 67         /// <value>The items.</value>
 68         [Description("节点列表"), Category("自定义")]
 69         public NavigationMenuItem[] Items
 70         {
 71             get { return items; }
 72             set
 73             {
 74                 items = value;
 75                 ReloadMenu();
 76             }
 77         }
 78
 79         /// <summary>
 80         /// The tip color
 81         /// </summary>
 82         private Color tipColor = Color.FromArgb(255, 87, 34);
 83
 84         /// <summary>
 85         /// Gets or sets the color of the tip.
 86         /// </summary>
 87         /// <value>The color of the tip.</value>
 88         [Description("角标颜色"), Category("自定义")]
 89         public Color TipColor
 90         {
 91             get { return tipColor; }
 92             set { tipColor = value; }
 93         }
 94
 95         /// <summary>
 96         /// 获取或设置控件的前景色。
 97         /// </summary>
 98         /// <value>The color of the fore.</value>
 99         /// <PermissionSet>
100         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
101         /// </PermissionSet>
102         public override System.Drawing.Color ForeColor
103         {
104             get
105             {
106                 return base.ForeColor;
107             }
108             set
109             {
110                 base.ForeColor = value;
111                 foreach (Control c in this.Controls)
112                 {
113                     c.ForeColor = value;
114                 }
115             }
116         }
117         /// <summary>
118         /// 获取或设置控件显示的文字的字体。
119         /// </summary>
120         /// <value>The font.</value>
121         /// <PermissionSet>
122         ///   <IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
123         ///   <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
124         ///   <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence" />
125         ///   <IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
126         /// </PermissionSet>
127         public override Font Font
128         {
129             get
130             {
131                 return base.Font;
132             }
133             set
134             {
135                 base.Font = value;
136                 foreach (Control c in this.Controls)
137                 {
138                     c.Font = value;
139                 }
140             }
141         }
142
143         /// <summary>
144         /// The m LST anchors
145         /// </summary>
146         Dictionary<NavigationMenuItem, FrmAnchor> m_lstAnchors = new Dictionary<NavigationMenuItem, FrmAnchor>();
147
148         /// <summary>
149         /// Initializes a new instance of the <see cref="UCNavigationMenu"/> class.
150         /// </summary>
151         public UCNavigationMenu()
152         {
153             InitializeComponent();
154             items = new NavigationMenuItem[0];
155             if (ControlHelper.IsDesignMode())
156             {
157                 items = new NavigationMenuItem[4];
158                 for (int i = 0; i < 4; i++)
159                 {
160                     items[i] = new NavigationMenuItem()
161                     {
162                         Text = "菜单" + (i + 1),
163                         AnchorRight = i >= 2
164                     };
165                 }
166             }
167         }
168
169         /// <summary>
170         /// Reloads the menu.
171         /// </summary>
172         private void ReloadMenu()
173         {
174             try
175             {
176                 ControlHelper.FreezeControl(this, true);
177                 this.Controls.Clear();
178                 if (items != null && items.Length > 0)
179                 {
180                     foreach (var item in items)
181                     {
182                         var menu = (NavigationMenuItem)item;
183                         Label lbl = new Label();
184                         lbl.AutoSize = false;
185                         lbl.TextAlign = ContentAlignment.MiddleCenter;
186                         lbl.Width = menu.ItemWidth;
187                         lbl.Text = menu.Text;
188
189                         lbl.Font = Font;
190                         lbl.ForeColor = ForeColor;
191
192                         lbl.Paint += lbl_Paint;
193                         lbl.MouseEnter += lbl_MouseEnter;
194                         lbl.Tag = menu;
195                         lbl.Click += lbl_Click;
196                         if (menu.AnchorRight)
197                         {
198                             lbl.Dock = DockStyle.Right;
199                         }
200                         else
201                         {
202                             lbl.Dock = DockStyle.Left;
203                         }
204                         this.Controls.Add(lbl);
205
206                         lbl.BringToFront();
207                     }
208
209
210                 }
211             }
212             finally
213             {
214                 ControlHelper.FreezeControl(this, false);
215             }
216         }
217
218
219
220         /// <summary>
221         /// Handles the Click event of the lbl control.
222         /// </summary>
223         /// <param name="sender">The source of the event.</param>
224         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
225         void lbl_Click(object sender, EventArgs e)
226         {
227             Label lbl = sender as Label;
228             if (lbl.Tag != null)
229             {
230                 var menu = (NavigationMenuItem)lbl.Tag;
231                 if (menu.Items == null || menu.Items.Length <= 0)
232                 {
233                     selectItem = menu;
234
235                     while (m_lstAnchors.Count > 0)
236                     {
237                         try
238                         {
239                             foreach (var item in m_lstAnchors)
240                             {
241                                 item.Value.Close();
242                                 m_lstAnchors.Remove(item.Key);
243                             }
244                         }
245                         catch { }
246                     }
247
248                     if (ClickItemed != null)
249                     {
250                         ClickItemed(this, e);
251                     }
252                 }
253                 else
254                 {
255                     CloseList(menu);
256                     if (m_lstAnchors.ContainsKey(menu))
257                     {
258                         if (m_lstAnchors[menu] != null && !m_lstAnchors[menu].IsDisposed)
259                         {
260                             m_lstAnchors[menu].Close();
261                         }
262                         m_lstAnchors.Remove(menu);
263                     }
264                     ShowMoreMenu(lbl);
265                 }
266             }
267         }
268
269         /// <summary>
270         /// Handles the MouseEnter event of the lbl control.
271         /// </summary>
272         /// <param name="sender">The source of the event.</param>
273         /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
274         void lbl_MouseEnter(object sender, EventArgs e)
275         {
276             Label lbl = sender as Label;
277             ShowMoreMenu(lbl);
278         }
279
280         /// <summary>
281         /// Checks the show.
282         /// </summary>
283         /// <param name="menu">The menu.</param>
284         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
285         private bool CheckShow(NavigationMenuItem menu)
286         {
287             //检查已经打开的节点
288             if (m_lstAnchors.ContainsKey(menu))
289             {
290                 CloseList(menu);
291                 return false;
292             }
293             if (HasInCacheChild(menu))
294             {
295                 if (m_lstAnchors.ContainsKey(menu.ParentItem))
296                 {
297                     CloseList(menu.ParentItem);
298                     return true;
299                 }
300                 return false;
301             }
302             else
303             {
304                 for (int i = 0; i < 1; )
305                 {
306                     try
307                     {
308                         foreach (var item in m_lstAnchors)
309                         {
310                             if (m_lstAnchors[item.Key] != null && !m_lstAnchors[item.Key].IsDisposed)
311                             {
312                                 m_lstAnchors[item.Key].Close();
313                             }
314                         }
315                     }
316                     catch
317                     {
318                         continue;
319                     }
320                     i++;
321                 }
322                 m_lstAnchors.Clear();
323                 return true;
324             }
325         }
326
327         /// <summary>
328         /// Determines whether [has in cache child] [the specified menu].
329         /// </summary>
330         /// <param name="menu">The menu.</param>
331         /// <returns><c>true</c> if [has in cache child] [the specified menu]; otherwise, <c>false</c>.</returns>
332         private bool HasInCacheChild(NavigationMenuItem menu)
333         {
334             foreach (var item in m_lstAnchors)
335             {
336                 if (item.Key == menu)
337                 {
338                     return true;
339                 }
340                 else
341                 {
342                     if (item.Key.Items != null)
343                     {
344                         if (item.Key.Items.Contains(menu))
345                             return true;
346                     }
347                 }
348             }
349             return false;
350         }
351
352         /// <summary>
353         /// Closes the list.
354         /// </summary>
355         /// <param name="menu">The menu.</param>
356         private void CloseList(NavigationMenuItem menu)
357         {
358             if (menu.Items != null)
359             {
360                 foreach (var item in menu.Items)
361                 {
362                     CloseList(item);
363                     if (m_lstAnchors.ContainsKey(item))
364                     {
365                         if (m_lstAnchors[item] != null && !m_lstAnchors[item].IsDisposed)
366                         {
367                             m_lstAnchors[item].Close();
368                             m_lstAnchors[item] = null;
369                             m_lstAnchors.Remove(item);
370                         }
371                     }
372                 }
373             }
374         }
375
376         /// <summary>
377         /// Shows the more menu.
378         /// </summary>
379         /// <param name="lbl">The label.</param>
380         private void ShowMoreMenu(Label lbl)
381         {
382             var menu = (NavigationMenuItem)lbl.Tag;
383             if (CheckShow(menu))
384             {
385                 if (menu.Items != null && menu.Items.Length > 0)
386                 {
387                     Panel panel = new Panel();
388                     panel.BackColor = Color.White;
389                     panel.Paint += panel_Paint;
390                     panel.Padding = new System.Windows.Forms.Padding(1);
391                     Size size = GetItemsSize(menu.Items);
392                     var height = size.Height * menu.Items.Length + 2;
393                     height += menu.Items.Count(p => p.HasSplitLintAtTop);//分割线
394                     if (size.Width < lbl.Width)
395                         size.Width = lbl.Width;
396                     panel.Size = new Size(size.Width, height);
397
398                     foreach (var item in menu.Items)
399                     {
400                         if (item.HasSplitLintAtTop)
401                         {
402                             UCSplitLine_H line = new UCSplitLine_H();
403                             line.Dock = DockStyle.Top;
404                             panel.Controls.Add(line);
405                             line.BringToFront();
406                         }
407                         Label _lbl = new Label();
408                         _lbl.Font = Font;
409                         _lbl.ForeColor = this.BackColor;
410                         _lbl.AutoSize = false;
411                         _lbl.TextAlign = ContentAlignment.MiddleCenter;
412                         _lbl.Height = size.Height;
413                         _lbl.Text = item.Text;
414                         _lbl.Dock = DockStyle.Top;
415                         _lbl.BringToFront();
416                         _lbl.Paint += lbl_Paint;
417                         _lbl.MouseEnter += lbl_MouseEnter;
418                         _lbl.Tag = item;
419                         _lbl.Click += lbl_Click;
420                         _lbl.Size = new System.Drawing.Size(size.Width, size.Height);
421                         panel.Controls.Add(_lbl);
422                         _lbl.BringToFront();
423                     }
424                     Point point = Point.Empty;
425
426                     if (menu.ParentItem != null)
427                     {
428                         Point p = lbl.Parent.PointToScreen(lbl.Location);
429                         if (p.X + lbl.Width + panel.Width > Screen.PrimaryScreen.Bounds.Width)
430                         {
431                             point = new Point(-1 * panel.Width - 2, -1 * lbl.Height);
432                         }
433                         else
434                         {
435                             point = new Point(panel.Width + 2, -1 * lbl.Height);
436                         }
437                     }
438                     m_lstAnchors[menu] = new FrmAnchor(lbl, panel, point);
439                     m_lstAnchors[menu].FormClosing += UCNavigationMenu_FormClosing;
440                     m_lstAnchors[menu].Show();
441                     m_lstAnchors[menu].Size = new Size(size.Width, height);
442                 }
443             }
444
445         }
446
447         /// <summary>
448         /// Handles the FormClosing event of the UCNavigationMenu control.
449         /// </summary>
450         /// <param name="sender">The source of the event.</param>
451         /// <param name="e">The <see cref="FormClosingEventArgs"/> instance containing the event data.</param>
452         void UCNavigationMenu_FormClosing(object sender, FormClosingEventArgs e)
453         {
454             FrmAnchor frm = sender as FrmAnchor;
455             if (m_lstAnchors.ContainsValue(frm))
456             {
457                 foreach (var item in m_lstAnchors)
458                 {
459                     if (item.Value == frm)
460                     {
461                         m_lstAnchors.Remove(item.Key);
462                         return;
463                     }
464                 }
465             }
466         }
467
468         /// <summary>
469         /// Handles the Paint event of the panel control.
470         /// </summary>
471         /// <param name="sender">The source of the event.</param>
472         /// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
473         void panel_Paint(object sender, PaintEventArgs e)
474         {
475             e.Graphics.SetGDIHigh();
476             Rectangle rect = new Rectangle(0, 0, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1);
477             var path = rect.CreateRoundedRectanglePath(2);
478             e.Graphics.DrawPath(new Pen(new SolidBrush(LineColors.Light)), path);
479         }
480
481
482
483         /// <summary>
484         /// Gets the size of the items.
485         /// </summary>
486         /// <param name="items">The items.</param>
487         /// <returns>Size.</returns>
488         private Size GetItemsSize(NavigationMenuItem[] items)
489         {
490             Size size = Size.Empty;
491             if (items != null && items.Length > 0)
492             {
493                 using (var g = this.CreateGraphics())
494                 {
495                     foreach (NavigationMenuItem item in items)
496                     {
497                         var s = g.MeasureString(item.Text, Font);
498                         if (s.Width + 25 > size.Width)
499                         {
500                             size.Width = (int)s.Width + 25;
501                         }
502                         if (s.Height + 10 > size.Height)
503                         {
504                             size.Height = (int)s.Height + 10;
505                         }
506                     }
507                 }
508             }
509             return size;
510         }
511
512
513         /// <summary>
514         /// Handles the Paint event of the lbl control.
515         /// </summary>
516         /// <param name="sender">The source of the event.</param>
517         /// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
518         void lbl_Paint(object sender, PaintEventArgs e)
519         {
520             Label lbl = sender as Label;
521             if (lbl.Tag != null)
522             {
523                 var menu = (NavigationMenuItem)lbl.Tag;
524                 e.Graphics.SetGDIHigh();
525                 if (menu.ParentItem == null)//顶级节点支持图标和角标
526                 {
527                     if (menu.ShowTip)
528                     {
529                         if (!string.IsNullOrEmpty(menu.TipText))
530                         {
531                             var rect = new Rectangle(lbl.Width - 25, lbl.Height / 2 - 10, 20, 20);
532                             var path = rect.CreateRoundedRectanglePath(5);
533                             e.Graphics.FillPath(new SolidBrush(tipColor), path);
534                             e.Graphics.DrawString(menu.TipText, new Font("微软雅黑", 8f), new SolidBrush(Color.White), rect, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
535                         }
536                         else
537                         {
538                             e.Graphics.FillEllipse(new SolidBrush(tipColor), new Rectangle(lbl.Width - 20, lbl.Height / 2 - 10, 10, 10));
539                         }
540                     }
541                     if (menu.Icon != null)
542                     {
543                         e.Graphics.DrawImage(menu.Icon, new Rectangle(1, (lbl.Height - 25) / 2, 25, 25), 0, 0, menu.Icon.Width, menu.Icon.Height, GraphicsUnit.Pixel);
544                     }
545                 }
546                 if (menu.ParentItem != null && menu.Items != null && menu.Items.Length > 0)
547                 {
548                     ControlHelper.PaintTriangle(e.Graphics, new SolidBrush(this.BackColor), new Point(lbl.Width - 11, (lbl.Height - 5) / 2), 5, GraphDirection.Rightward);
549                 }
550             }
551         }
552     }
553 }

最后的话

如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星星吧

原文地址:https://www.cnblogs.com/bfyx/p/11639401.html

时间: 2024-10-12 03:12:55

(七十九)c#Winform自定义控件-导航菜单的相关文章

(七十)c#Winform自定义控件-饼状图

前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 如果觉得写的还行,请点个 star 支持一下吧 欢迎前来交流探讨: 企鹅群568015492  麻烦博客下方点个[推荐],谢谢 NuGet Install-Package HZH_Con

第三百七十九节,Django+Xadmin打造上线标准的在线教育平台—xadmin的安装

第三百七十九节,Django+Xadmin打造上线标准的在线教育平台-xadmin的安装 xadmin介绍 xadmin是基于Django的admin开发的更完善的后台管理系统

C#之 十九 使用WinForm控件

十九 使用Win Form控件 比如说电脑有显示器,鼠标,主机以及键盘的基本元素组成.在windows窗体中也有其基本控件,这些控件在每一个窗体中都要用到,也就是说无所不在.有些控件可能外观不同但是他们的使用方式都基本上一样. 重点 ?        掌握这些控件常用属性方法以及事件 ?        能用编码的形式实现控件的基本功能 ?        体会每个控件使用的场景 预习功课 ?        什么是控件类,控件类的基类(父类)是么?它是用来做什么的? ?        标签,按钮,文

Android实战简易教程-第六十九枪(自定义控件实现雪花飘落效果)

现在APP要求越来越高了,不只是要求实现功能,颜值的要求也越来越高,下面我们通过自定义控件来实现雪花飘落的效果,可以作为界面背景哦. 1.自定义控件: package com.test.a; import java.util.Random; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Can

(十)c#Winform自定义控件-列表

前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control 如果觉得写的还行,请点个 star 支持一下吧 欢迎前来交流探讨: 企鹅群568015492  准备工作 列表控件将被拆分为2部分,一个元素,一个列表,列表需要支持主副标题,图标等 开始 首先定义一个数据源类(其实更好的是应该接受object,然后通过绑定字段反射绑定数据,这样就不需要这个数据源类

(六十)c#Winform自定义控件-鼓风机(工业)

前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git 如果觉得写的还行,请点个 star 支持一下吧 欢迎前来交流探讨: 企鹅群568015492  麻烦博客下方点个[推荐],谢谢 NuGet Install-Package HZH_Con

一起talk C栗子吧(第一百七十九回:C语言实例--字符和字符串输出函数二)

各位看官们,大家好,上一回中咱们说的是字符和字符串输出函数的例子,这一回咱们继续说该例子.闲 话休提,言归正转.让我们一起talk C栗子吧! 看官们,我们在上一回中介绍了字符和字符串输出函数的用法,満篇都是理论,古语云:纸上得来终觉浅,绝知此事要躬行.这一回中我们要把这些纸上得来理论应用于实践中,让我们一起动手去实践吧. 接下来,我们将通过具体的代码来说明如何使用字符输出函数,以及使用时的注意事项: int main() { char ch = 'a'; char *str = "hello

第一百七十九节,jQuery-UI,知问前端--按钮 UI

jQuery-UI,知问前端--按钮 UI 学习要点: 1.使用 button 按钮 2.修改 button 样式 3.button()方法的属性 4.button('action', param) 5.单选.复选按钮 按钮(button),可以给生硬的原生按钮或者文本提供更多丰富多彩的外观.它不单单 可以设置按钮或文本,还可以设置单选按钮和多选按钮. 一.使用 button 按钮 使用 button 按钮 UI 的时候,不一定必须是 input 按钮形式,普通的文本也可以设置成 button

053(七十九)

391. 391.When setting up the Flashback Data Archive, which of these key parameters are required? (Choose all that apply.) A. Tablespace name B. Storage quota C. Retention D. Table name E. Create a default archive 392. 392.To clean up old records that