(十三)c#Winform自定义控件-导航菜单
官网
前提
入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果觉得写的还行,请点个 star 支持一下吧
欢迎前来交流探讨: 企鹅群568015492 idkey=6e08741ef16fe53bf0314c1c9e336c4f626047943a8b76bac062361bab6b4f8d">
目录
https://www.cnblogs.com/bfyx/p/11364884.html
准备工作
有时候我们需要左侧的导航菜单,那么来整一个吧
先来分析分析,导航菜单一般分为2级或多级,如果是多级的话 用前面的treeview更合适,这里只做2级,为了父子节点样式更方便控制,我们分别实现父子节点。
为了更加的Open,我们使用接口来定义一下
开始
定义一个节点数据绑定实体
[Serializable]
public class MenuItemEntity
{
/// <summary>
/// 键
/// </summary>
public string Key { get; set; }
/// <summary>
/// 文字
/// </summary>
public string Text { get; set; }
/// <summary>
/// 子节点
/// </summary>
public List<MenuItemEntity> Childrens { get; set; }
/// <summary>
/// 自定义数据源,一般用于扩展展示,比如定义节点图片等
/// </summary>
public object DataSource { get; set; } }
再定义一个接口来约束
public interface IMenuItem
{
event EventHandler SelectedItem;
MenuItemEntity DataSource { get; set; }
/// <summary>
/// 设置样式
/// </summary>
/// <param name="styles">key:属性名称,value:属性值</param>
void SetStyle(Dictionary<string, object> styles);
/// <summary>
/// 设置选中样式
/// </summary>
/// <param name="blnSelected">是否选中</param>
void SetSelectedStyle(bool blnSelected);
}
首先看父节点定义,添加一个用户控件,命名UCMenuParentItem,并且实现接口IMenuItem
public event EventHandler SelectedItem;
private MenuItemEntity m_dataSource;
public MenuItemEntity DataSource
{
get
{
return m_dataSource;
}
set
{
m_dataSource = value;
if (value != null)
{
lblTitle.Text = value.Text;
}
}
}
public void SetStyle(Dictionary<string, object> styles)
{
Type t = this.GetType();
foreach (var item in styles)
{
var pro = t.GetProperty(item.Key);
if (pro != null && pro.CanWrite)
{
try
{
pro.SetValue(this, item.Value, null);
}
catch (Exception ex)
{
throw new Exception("菜单元素设置样式异常", ex);
}
}
}
}
public void SetSelectedStyle(bool blnSelected)
{
if (blnSelected)
{
this.lblTitle.Image = Properties.Resources.sanjiao1;
}
else
{
this.lblTitle.Image = Properties.Resources.sanjiao2;
}
}
然后处理下点击事件
lblTitle.MouseDown += lblTitle_MouseDown; void lblTitle_MouseDown(object sender, MouseEventArgs e)
{
if (SelectedItem != null)
{
SelectedItem(this, e);
}
}
这样就完事了,看下完整代码
// 版权所有 黄正辉 交流群:568015492 QQ:623128629
// 文件名称:UCMenuParentItem.cs
// 创建日期:2019-08-15 16:02:35
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace HZH_Controls.Controls
{
/// <summary>
/// 父类节点
/// </summary>
[ToolboxItem(false)]
public partial class UCMenuParentItem : UserControl, IMenuItem
{
public event EventHandler SelectedItem; private MenuItemEntity m_dataSource;
public MenuItemEntity DataSource
{
get
{
return m_dataSource;
}
set
{
m_dataSource = value;
if (value != null)
{
lblTitle.Text = value.Text;
}
}
} public UCMenuParentItem()
{
InitializeComponent();
lblTitle.MouseDown += lblTitle_MouseDown;
} public void SetStyle(Dictionary<string, object> styles)
{
Type t = this.GetType();
foreach (var item in styles)
{
var pro = t.GetProperty(item.Key);
if (pro != null && pro.CanWrite)
{
try
{
pro.SetValue(this, item.Value, null);
}
catch (Exception ex)
{
throw new Exception("菜单元素设置样式异常", ex);
}
}
}
} public void SetSelectedStyle(bool blnSelected)
{
if (blnSelected)
{
this.lblTitle.Image = Properties.Resources.sanjiao1;
}
else
{
this.lblTitle.Image = Properties.Resources.sanjiao2;
}
} void lblTitle_MouseDown(object sender, MouseEventArgs e)
{
if (SelectedItem != null)
{
SelectedItem(this, e);
}
}
}
}
namespace HZH_Controls.Controls
{
partial class UCMenuParentItem
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region 组件设计器生成的代码 /// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
this.lblTitle = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// ucSplitLine_H1
//
this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.ucSplitLine_H1.Location = new System.Drawing.Point(, );
this.ucSplitLine_H1.Name = "ucSplitLine_H1";
this.ucSplitLine_H1.Size = new System.Drawing.Size(, );
this.ucSplitLine_H1.TabIndex = ;
this.ucSplitLine_H1.TabStop = false;
//
// lblTitle
//
this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblTitle.ForeColor = System.Drawing.Color.White;
this.lblTitle.Image = global::HZH_Controls.Properties.Resources.sanjiao2;
this.lblTitle.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
this.lblTitle.Location = new System.Drawing.Point(, );
this.lblTitle.Name = "lblTitle";
this.lblTitle.Size = new System.Drawing.Size(, );
this.lblTitle.TabIndex = ;
this.lblTitle.Text = "父项";
this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// UCMenuParentItem
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.ucSplitLine_H1);
this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.Name = "UCMenuParentItem";
this.Size = new System.Drawing.Size(, );
this.ResumeLayout(false); } #endregion private UCSplitLine_H ucSplitLine_H1;
private System.Windows.Forms.Label lblTitle;
}
}
设计效果就是这样子的了

父节点弄好了,下面就是子节点了
添加用户控件,命名UCMenuChildrenItem,实现接口IMenuItem
public event EventHandler SelectedItem;
private MenuItemEntity m_dataSource;
public MenuItemEntity DataSource
{
get
{
return m_dataSource;
}
set
{
m_dataSource = value;
if (value != null)
{
lblTitle.Text = value.Text;
}
}
}
public void SetStyle(Dictionary<string, object> styles)
{
Type t = this.GetType();
foreach (var item in styles)
{
var pro = t.GetProperty(item.Key);
if (pro != null && pro.CanWrite)
{
try
{
pro.SetValue(this, item.Value, null);
}
catch (Exception ex)
{
throw new Exception("菜单元素设置样式异常", ex);
}
}
}
}
处理下点击事件
this.lblTitle.MouseDown += lblTitle_MouseDown;
void lblTitle_MouseDown(object sender, MouseEventArgs e)
{
if (SelectedItem != null)
{
SelectedItem(this, null);
}
}
这样就完成了,看下完整代码
// 版权所有 黄正辉 交流群:568015492 QQ:623128629
// 文件名称:UCMenuChildrenItem.cs
// 创建日期:2019-08-15 16:02:26
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace HZH_Controls.Controls
{
/// <summary>
/// 子类节点
/// </summary>
[ToolboxItem(false)]
public partial class UCMenuChildrenItem : UserControl, IMenuItem
{
public event EventHandler SelectedItem; private MenuItemEntity m_dataSource;
public MenuItemEntity DataSource
{
get
{
return m_dataSource;
}
set
{
m_dataSource = value;
if (value != null)
{
lblTitle.Text = value.Text;
}
}
}
public UCMenuChildrenItem()
{
InitializeComponent();
this.lblTitle.MouseDown += lblTitle_MouseDown;
} void lblTitle_MouseDown(object sender, MouseEventArgs e)
{
if (SelectedItem != null)
{
SelectedItem(this, null);
}
} public void SetStyle(Dictionary<string, object> styles)
{
Type t = this.GetType();
foreach (var item in styles)
{
var pro = t.GetProperty(item.Key);
if (pro != null && pro.CanWrite)
{
try
{
pro.SetValue(this, item.Value, null);
}
catch (Exception ex)
{
throw new Exception("菜单元素设置样式异常", ex);
}
}
}
} public void SetSelectedStyle(bool blnSelected)
{ }
}
}
namespace HZH_Controls.Controls
{
partial class UCMenuChildrenItem
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region 组件设计器生成的代码 /// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.ucSplitLine_H1 = new HZH_Controls.Controls.UCSplitLine_H();
this.lblTitle = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// ucSplitLine_H1
//
this.ucSplitLine_H1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.ucSplitLine_H1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.ucSplitLine_H1.Location = new System.Drawing.Point(, );
this.ucSplitLine_H1.Name = "ucSplitLine_H1";
this.ucSplitLine_H1.Size = new System.Drawing.Size(, );
this.ucSplitLine_H1.TabIndex = ;
this.ucSplitLine_H1.TabStop = false;
//
// lblTitle
//
this.lblTitle.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 12F);
this.lblTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.lblTitle.Location = new System.Drawing.Point(, );
this.lblTitle.Name = "lblTitle";
this.lblTitle.Size = new System.Drawing.Size(, );
this.lblTitle.TabIndex = ;
this.lblTitle.Text = "子项";
this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// UCMenuChildrenItem
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.ucSplitLine_H1);
this.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.Name = "UCMenuChildrenItem";
this.Size = new System.Drawing.Size(, );
this.ResumeLayout(false); } #endregion private UCSplitLine_H ucSplitLine_H1;
private System.Windows.Forms.Label lblTitle; }
}
设计效果是这样子的

你们有没有发现,父节点和子节点代码非常的相似呢?是的,基本上都是一样的,他们都实现了接口IMenuItem,
那既然如此为什么还要分为2个,这不是代码冗余了吗?这么做的好处就是你可以更方便的控制节点的设计样式,假如有一天,子节点你不想用文字了,你先够用图片呢?
到此,节点定义已经完成了,剩下的就是处理列表了,继续往下看吧。
定义一个用户控件,命名UCMenu
首先定义一个枚举
public enum MenuStyle
{
/// <summary>
/// 平铺
/// </summary>
Fill = ,
/// <summary>
/// 顶部对齐
/// </summary>
Top = ,
}
这个枚举的作用就是改变样式,默认是Fill,也就是子节点面板填充铺满,选中父节点上面的兄弟节点顶端对齐,下面的兄弟节点低端对齐,当父节点较多时候就会出现子节点无法显示的问题,这个时候使用Top就可以了,所有父节点顶端对齐
先看下有哪些属性
/// <summary>
/// 选中项事件
/// </summary>
public event EventHandler SelectedItem;
private Type m_parentItemType = typeof(UCMenuParentItem);
/// <summary>
/// 父类节点类型
/// </summary>
public Type ParentItemType
{
get { return m_parentItemType; }
set
{
if (value == null)
return;
if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
throw new Exception("节点控件没有实现IMenuItem接口");
m_parentItemType = value; }
} private Type m_childrenItemType = typeof(UCMenuChildrenItem);
/// <summary>
/// 子类节点类型
/// </summary>
public Type ChildrenItemType
{
get { return m_childrenItemType; }
set
{
if (value == null)
return;
if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
throw new Exception("节点控件没有实现IMenuItem接口");
m_childrenItemType = value;
}
} private Dictionary<string, object> m_parentItemStyles;
/// <summary>
/// 父类节点样式设置,key:属性名称,value:属性值
/// </summary>
public Dictionary<string, object> ParentItemStyles
{
get { return m_parentItemStyles; }
set { m_parentItemStyles = value; }
} private Dictionary<string, object> m_childrenItemStyles;
/// <summary>
/// 子类节点样式设置,key:属性名称,value:属性值
/// </summary>
public Dictionary<string, object> ChildrenItemStyles
{
get { return m_childrenItemStyles; }
set { m_childrenItemStyles = value; }
} private List<MenuItemEntity> m_dataSource;
/// <summary>
/// 数据源
/// </summary>
public List<MenuItemEntity> DataSource
{
get { return m_dataSource; }
set
{
m_dataSource = value; ReloadItems();
}
}
private bool m_isShowFirstItem = true;
/// <summary>
/// 是否自动展开第一个节点
/// </summary>
public bool IsShowFirstItem
{
get { return m_isShowFirstItem; }
set { m_isShowFirstItem = value; }
} private MenuStyle m_menuStyle = MenuStyle.Fill;
/// <summary>
/// 菜单样式
/// </summary>
public MenuStyle MenuStyle
{
get { return m_menuStyle; }
set { m_menuStyle = value; }
} private List<Control> m_lstParentItems = new List<Control>(); private IMenuItem m_selectParentItem = null;
private IMenuItem m_selectChildrenItem = null; private Panel m_panChildren = null;
数据源改变时需要重新加载
private void ReloadItems()
{
try
{
ControlHelper.FreezeControl(this, true);
this.Controls.Clear();
m_lstParentItems.Clear();
if (m_dataSource != null && m_dataSource.Count > )
{
foreach (var parent in m_dataSource)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
parentItem.DataSource = parent;
if (m_parentItemStyles != null)
parentItem.SetStyle(m_parentItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
c.Dock = DockStyle.Top;
this.Controls.Add(c);
this.Controls.SetChildIndex(c, );
m_lstParentItems.Add(c);
}
}
m_panChildren = new Panel();
if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
{
m_panChildren.Dock = DockStyle.Fill;
m_panChildren.Height = ;
}
else
{
m_panChildren.Dock = DockStyle.Top;
m_panChildren.Height = ;
}
m_panChildren.AutoScroll = true;
this.Controls.Add(m_panChildren);
}
finally
{
ControlHelper.FreezeControl(this, false);
} if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > )
{
parentItem_SelectedItem(m_lstParentItems[], null);
}
}
选中父节点时候加载子节点
void parentItem_SelectedItem(object sender, EventArgs e)
{
this.FindForm().ActiveControl = this;
IMenuItem item = sender as IMenuItem;
if (m_lstParentItems.Contains(sender as Control))
{
if (m_selectParentItem != item)
{
if (m_selectParentItem != null)
{
m_selectParentItem.SetSelectedStyle(false);
}
m_selectParentItem = item;
m_selectParentItem.SetSelectedStyle(true);
SetChildrenControl(m_selectParentItem);
}
else
{
m_selectParentItem.SetSelectedStyle(false);
m_selectParentItem = null;
SetChildrenControl(m_selectParentItem, false);
}
}
else if (m_panChildren.Controls.Contains(sender as Control))
{
if (m_selectChildrenItem != item)
{
if (m_selectChildrenItem != null)
{
m_selectChildrenItem.SetSelectedStyle(false);
}
m_selectChildrenItem = item;
m_selectChildrenItem.SetSelectedStyle(true);
}
}
if (SelectedItem != null)
{
SelectedItem(sender, e);
}
} private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
{
try
{
ControlHelper.FreezeControl(this, true);
if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
{
if (blnChildren)
{
Control cMenu = menuitem as Control;
int index = m_lstParentItems.IndexOf(cMenu);
for (int i = ; i <= index; i++)
{
m_lstParentItems[i].Dock = DockStyle.Top;
this.Controls.SetChildIndex(m_lstParentItems[i], );
}
for (int i = index + ; i < m_lstParentItems.Count; i++)
{
m_lstParentItems[i].Dock = DockStyle.Bottom;
this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
}
m_panChildren.Controls.Clear();
int intItemHeigth = ;
foreach (var item in menuitem.DataSource.Childrens)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
parentItem.DataSource = item;
if (m_childrenItemStyles != null)
parentItem.SetStyle(m_childrenItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
if (intItemHeigth == )
intItemHeigth = c.Height;
c.Dock = DockStyle.Top;
m_panChildren.Controls.Add(c);
m_panChildren.Controls.SetChildIndex(c, );
}
//m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
}
else
{
m_panChildren.Controls.Clear();
foreach (var item in m_lstParentItems)
{
item.Dock = DockStyle.Top;
this.Controls.SetChildIndex(item, );
}
}
}
else
{
if (blnChildren)
{
Control cMenu = menuitem as Control;
int index = m_lstParentItems.IndexOf(cMenu);
this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - );
m_panChildren.Controls.Clear();
int intItemHeigth = ;
foreach (var item in menuitem.DataSource.Childrens)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
parentItem.DataSource = item;
if (m_childrenItemStyles != null)
parentItem.SetStyle(m_childrenItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
if (intItemHeigth == )
intItemHeigth = c.Height;
c.Dock = DockStyle.Top;
m_panChildren.Controls.Add(c);
m_panChildren.Controls.SetChildIndex(c, );
}
m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
}
else
{
m_panChildren.Controls.Clear();
m_panChildren.Height = ;
}
}
}
finally
{
ControlHelper.FreezeControl(this, false);
}
}
代码就这么多,看下完整代码
// 版权所有 黄正辉 交流群:568015492 QQ:623128629
// 文件名称:UCMenu.cs
// 创建日期:2019-08-15 16:02:22
// 功能描述:Menu
// 项目地址:https://gitee.com/kwwwvagaa/net_winform_custom_control
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace HZH_Controls.Controls
{
public partial class UCMenu : UserControl
{
/// <summary>
/// 选中项事件
/// </summary>
public event EventHandler SelectedItem;
private Type m_parentItemType = typeof(UCMenuParentItem);
/// <summary>
/// 父类节点类型
/// </summary>
public Type ParentItemType
{
get { return m_parentItemType; }
set
{
if (value == null)
return;
if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
throw new Exception("节点控件没有实现IMenuItem接口");
m_parentItemType = value; }
} private Type m_childrenItemType = typeof(UCMenuChildrenItem);
/// <summary>
/// 子类节点类型
/// </summary>
public Type ChildrenItemType
{
get { return m_childrenItemType; }
set
{
if (value == null)
return;
if (!typeof(IMenuItem).IsAssignableFrom(value) || !value.IsSubclassOf(typeof(Control)))
throw new Exception("节点控件没有实现IMenuItem接口");
m_childrenItemType = value;
}
} private Dictionary<string, object> m_parentItemStyles;
/// <summary>
/// 父类节点样式设置,key:属性名称,value:属性值
/// </summary>
public Dictionary<string, object> ParentItemStyles
{
get { return m_parentItemStyles; }
set { m_parentItemStyles = value; }
} private Dictionary<string, object> m_childrenItemStyles;
/// <summary>
/// 子类节点样式设置,key:属性名称,value:属性值
/// </summary>
public Dictionary<string, object> ChildrenItemStyles
{
get { return m_childrenItemStyles; }
set { m_childrenItemStyles = value; }
} private List<MenuItemEntity> m_dataSource;
/// <summary>
/// 数据源
/// </summary>
public List<MenuItemEntity> DataSource
{
get { return m_dataSource; }
set
{
m_dataSource = value; ReloadItems();
}
}
private bool m_isShowFirstItem = true;
/// <summary>
/// 是否自动展开第一个节点
/// </summary>
public bool IsShowFirstItem
{
get { return m_isShowFirstItem; }
set { m_isShowFirstItem = value; }
} private MenuStyle m_menuStyle = MenuStyle.Fill;
/// <summary>
/// 菜单样式
/// </summary>
public MenuStyle MenuStyle
{
get { return m_menuStyle; }
set { m_menuStyle = value; }
} private List<Control> m_lstParentItems = new List<Control>(); private IMenuItem m_selectParentItem = null;
private IMenuItem m_selectChildrenItem = null; private Panel m_panChildren = null; private void ReloadItems()
{
try
{
ControlHelper.FreezeControl(this, true);
this.Controls.Clear();
m_lstParentItems.Clear();
if (m_dataSource != null && m_dataSource.Count > )
{
foreach (var parent in m_dataSource)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_parentItemType);
parentItem.DataSource = parent;
if (m_parentItemStyles != null)
parentItem.SetStyle(m_parentItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
c.Dock = DockStyle.Top;
this.Controls.Add(c);
this.Controls.SetChildIndex(c, );
m_lstParentItems.Add(c);
}
}
m_panChildren = new Panel();
if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
{
m_panChildren.Dock = DockStyle.Fill;
m_panChildren.Height = ;
}
else
{
m_panChildren.Dock = DockStyle.Top;
m_panChildren.Height = ;
}
m_panChildren.AutoScroll = true;
this.Controls.Add(m_panChildren);
}
finally
{
ControlHelper.FreezeControl(this, false);
} if (m_isShowFirstItem && m_lstParentItems != null && m_lstParentItems.Count > )
{
parentItem_SelectedItem(m_lstParentItems[], null);
}
} void parentItem_SelectedItem(object sender, EventArgs e)
{
this.FindForm().ActiveControl = this;
IMenuItem item = sender as IMenuItem;
if (m_lstParentItems.Contains(sender as Control))
{
if (m_selectParentItem != item)
{
if (m_selectParentItem != null)
{
m_selectParentItem.SetSelectedStyle(false);
}
m_selectParentItem = item;
m_selectParentItem.SetSelectedStyle(true);
SetChildrenControl(m_selectParentItem);
}
else
{
m_selectParentItem.SetSelectedStyle(false);
m_selectParentItem = null;
SetChildrenControl(m_selectParentItem, false);
}
}
else if (m_panChildren.Controls.Contains(sender as Control))
{
if (m_selectChildrenItem != item)
{
if (m_selectChildrenItem != null)
{
m_selectChildrenItem.SetSelectedStyle(false);
}
m_selectChildrenItem = item;
m_selectChildrenItem.SetSelectedStyle(true);
}
}
if (SelectedItem != null)
{
SelectedItem(sender, e);
}
} private void SetChildrenControl(IMenuItem menuitem, bool blnChildren = true)
{
try
{
ControlHelper.FreezeControl(this, true);
if (m_menuStyle == HZH_Controls.Controls.MenuStyle.Fill)
{
if (blnChildren)
{
Control cMenu = menuitem as Control;
int index = m_lstParentItems.IndexOf(cMenu);
for (int i = ; i <= index; i++)
{
m_lstParentItems[i].Dock = DockStyle.Top;
this.Controls.SetChildIndex(m_lstParentItems[i], );
}
for (int i = index + ; i < m_lstParentItems.Count; i++)
{
m_lstParentItems[i].Dock = DockStyle.Bottom;
this.Controls.SetChildIndex(m_lstParentItems[i], m_lstParentItems.Count);
}
m_panChildren.Controls.Clear();
int intItemHeigth = ;
foreach (var item in menuitem.DataSource.Childrens)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
parentItem.DataSource = item;
if (m_childrenItemStyles != null)
parentItem.SetStyle(m_childrenItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
if (intItemHeigth == )
intItemHeigth = c.Height;
c.Dock = DockStyle.Top;
m_panChildren.Controls.Add(c);
m_panChildren.Controls.SetChildIndex(c, );
}
//m_panChildren.MinimumSize = new Size(0, menuitem.DataSource.Childrens.Count * intItemHeigth);
}
else
{
m_panChildren.Controls.Clear();
foreach (var item in m_lstParentItems)
{
item.Dock = DockStyle.Top;
this.Controls.SetChildIndex(item, );
}
}
}
else
{
if (blnChildren)
{
Control cMenu = menuitem as Control;
int index = m_lstParentItems.IndexOf(cMenu);
this.Controls.SetChildIndex(m_panChildren, m_lstParentItems.Count - index - );
m_panChildren.Controls.Clear();
int intItemHeigth = ;
foreach (var item in menuitem.DataSource.Childrens)
{
IMenuItem parentItem = (IMenuItem)Activator.CreateInstance(m_childrenItemType);
parentItem.DataSource = item;
if (m_childrenItemStyles != null)
parentItem.SetStyle(m_childrenItemStyles);
parentItem.SelectedItem += parentItem_SelectedItem;
Control c = parentItem as Control;
if (intItemHeigth == )
intItemHeigth = c.Height;
c.Dock = DockStyle.Top;
m_panChildren.Controls.Add(c);
m_panChildren.Controls.SetChildIndex(c, );
}
m_panChildren.Height = menuitem.DataSource.Childrens.Count * intItemHeigth;
}
else
{
m_panChildren.Controls.Clear();
m_panChildren.Height = ;
}
}
}
finally
{
ControlHelper.FreezeControl(this, false);
}
} public UCMenu()
{
InitializeComponent();
}
} public enum MenuStyle
{
/// <summary>
/// 平铺
/// </summary>
Fill = ,
/// <summary>
/// 顶部对齐
/// </summary>
Top = ,
} }
namespace HZH_Controls.Controls
{
partial class UCMenu
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region 组件设计器生成的代码 /// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// UCMenu
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.AutoScroll = true;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)()))), ((int)(((byte)()))), ((int)(((byte)()))));
this.Name = "UCMenu";
this.Size = new System.Drawing.Size(, );
this.ResumeLayout(false); } #endregion }
}
用处及效果

示例代码
List<MenuItemEntity> lstMenu = new List<MenuItemEntity>();
for (int i = ; i < ; i++)
{
MenuItemEntity item = new MenuItemEntity()
{
Key = "p" + i.ToString(),
Text = "菜单项" + i,
DataSource = "这里编写一些自定义的数据源,用于扩展"
};
item.Childrens = new List<MenuItemEntity>();
for (int j = ; j < ; j++)
{
MenuItemEntity item2 = new MenuItemEntity()
{
Key = "c" + i.ToString(),
Text = "菜单子项" + i + "-" + j,
DataSource = "这里编写一些自定义的数据源,用于扩展"
};
item.Childrens.Add(item2);
}
lstMenu.Add(item);
}
this.ucMenu1.MenuStyle = MenuStyle.Top;
this.ucMenu1.DataSource = lstMenu;
最后的话
如果你喜欢的话,请到 https://gitee.com/kwwwvagaa/net_winform_custom_control 点个星 星吧
(十三)c#Winform自定义控件-导航菜单的更多相关文章
- (七十九)c#Winform自定义控件-导航菜单
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (八十三)c#Winform自定义控件-导航菜单(扩展)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (八十四)c#Winform自定义控件-导航菜单(类Office菜单)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- c#Winform自定义控件-目录
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- winform 自定义控件(高手)
高手推荐:https://www.cnblogs.com/bfyx/p/11364884.html c#Winform自定义控件-目录 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件 ...
- (三十三)c#Winform自定义控件-日期控件
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- (二十三)c#Winform自定义控件-等待窗体
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- (七十三)c#Winform自定义控件-资源加载窗体
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (四十三)c#Winform自定义控件-Listview-HZHControls
官网 http://www.hzhcontrols.com 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kww ...
随机推荐
- 使用Optional摆脱NPE的折磨
在目前的工作中,我对Java中的Stream和Lambda表达式都使用得很多,之前也写了两篇文章来总结对应的知识. 024:Java流实现Shell:cat 1.log | grep a | sort ...
- Latch设计模式
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; public class Te ...
- MyBatis从入门到精通(十三):使用discriminator鉴别器映射
最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解鉴别器映射discri ...
- 客户端远程调用Feign
客户端远程调用 Feign 什么是Feign? Feign是 Netflix 公司开源的声明式HTTP客户端 Github : Feign 源码 为什么需要Feign? 原代码可读性不高 复杂的URL ...
- mimalloc内存分配代码分析
这篇文章中我们会介绍一下mimalloc的实现,其中可能涉及上一篇文章提到的内容,如果不了解的可以先看下这篇mimalloc剖析.首先我们需要了解的是其整体结构,mimalloc的结构如下图所示 ...
- [leetcode] 62 Unique Paths (Medium)
原题链接 字母题 : unique paths Ⅱ 思路: dp[i][j]保存走到第i,j格共有几种走法. 因为只能走→或者↓,所以边界条件dp[0][j]+=dp[0][j-1] 同时容易得出递推 ...
- 盘一盘 synchronized (二)—— 偏向锁批量重偏向与批量撤销
在本文讲解之前,先来简单了解一下为什么会有批量重偏向和批量撤销. 批量重偏向:当一个线程创建了大量对象并执行了初始的同步操作,后来另一个线程也来将这些对象作为锁对象进行操作,会导偏向锁重偏向的操作 ...
- Sting和Long类型转换
java String 转 Long 两种方法区别Long.ValueOf("String")返回Long包装类型包装类型: Byte,Integer,Short,Long,Boo ...
- gawk(awk)的用法案例
gawk(awk)的用法案例 本文首先简单介绍一个gawk和awk的区别,然后是一点基本使用流程,最后是自己做的一个分析数据文件的脚本代码,供大家参考.另外想了解基本流程的入门知识的可以下载附件pdf ...
- 使用Java实现数据库编程 项目(宠物商店)
创建数据库代码: DROP DATABASE IF EXISTS petShop; CREATE DATABASE petShop; USE petShop; /*创建表*/ CREATE TABLE ...