效果:

描述:

这是一个可折叠的菜单导航,主要是由panel、picturebox、label完成,界面的颜色用来区分一下各个组合控件,便于调试。
首先,首先是ImageButton:
这个是由PictureBox和Label构成。
1.文字部分的居中需要设置label的宽度为父容器的宽度。
2.图片设置 picBox.SizeMode = PictureBoxSizeMode.StretchImage
 
然后是单个的菜单 命名为:ButtonGroup:
顶部灰色的是一个label,绿色里面的是一个包含ImageButton的列表。
1.顶部这个label注册了一个click事件,是为了完成点击它的时候会展开。
 
最后是整个的菜单,就是由ButtonGroup组成的一个list,我给它命名为:CustomNavBar。
 
这里需要注意的是:
事件的封装,像这种自定义控件,都是要定义自定义事件,并且把它暴露出来,元控件触发的时候,才触发这个暴露出来的控件。代码类似这种:
private void PicBoxClick(object sender,EventArgs args)
{
PictureBoxClick?.Invoke(sender, this.text);
}
PicBoxClick是PictureBox控件的原生Click事件,PictureBoxClick是我们自己定义的事件,这个事件需要到控件外部注册,就像这样:
for (int i = 0; i < _listImageButton.Count; i++)
{
var imgButton = _listImageButton[i];
 
imgButton.Top = i * imgButton.Height;
imgButton.Left = 0;
 
imgButton.PictureBoxClick += ImgButton_PictureBoxClick;
 
ButtonArea.Controls.Add(imgButton);
}
这段代码中,_listImageButton是属于ButtonGroup控件里的集合,这样做,最终点击PictureBox的时候,其实是调用ImgButton_PictureBoxClick这个方法里的内容。
假如这个ButtonGroup已经是最外层的自定义控件了,那么这个ImgButton_PictureBoxClick就属于供这个完整的自定义控件使用人也就是客户自己自定义的事件了,这个里面的代码就可以根据不同的客户,内容就可以不同了。
因为这个控件最外层的自定义控件是CustomNavBar,所以在CustomNavbar里还自定义了一个相同委托的事件:
public delegate void ImageButtonClick(object o,string moduleName);
public event ImageButtonClick NavButtonClick;
 
 
这代码也是我从其他地方下载的,然后自己看了一篇,在自己敲的。敲的过程中,了解到了内部类的使用,最大的收获是:一般窗体都是要有partial修饰的,而InitializeComponent()方法都是放在自动生成的代码里的,做这个控件的时候,我还是自己第一次这样通过写代码的方式来初始化一个控件。

代码:

public partial class CustomNavBar : UserControl
{
public CustomNavBar()
{
InitializeComponent();
InitializeButtonGroup();
pnlMain.BackColor = Color.DarkOliveGreen;
ResetMenu();
}
private string _jsonString;
/// <summary>
///暴露接口,可从外部(数据库)获得菜单的信息
/// </summary>
public string JsonString
{
get { return _jsonString; }
set { _jsonString = value; }
} private List<ButtonGroup> listGroup;
private int currentItemIndex; public delegate void ImageButtonClick(object o,string moduleName); public event ImageButtonClick NavButtonClick; public void InitializeButtonGroup()
{
listGroup = new List<ButtonGroup>() {
new ButtonGroup("欢迎使用",
new List<ImageButton>()
{
new ImageButton("欢迎使用",Resources.LogoMain),
new ImageButton("员工信息管理",Resources.LogoManageEmployee)
}), new ButtonGroup("系统设置",
new List<ImageButton>(){
new ImageButton("部门管理", Resources.LogoManageDepartment)}), new ButtonGroup("退出系统",null)
};
ButtonGroup bgPre=null;
int sum = ;
for (int i = ; i < listGroup.Count; i++)
{
int height = bgPre == null ? : bgPre.Height;
sum += height;
var buttonGroup = listGroup[i]; buttonGroup.Tag = i; buttonGroup.SetButtonLocation(); buttonGroup.ImageButtonClick += new ImageButtonClick(NavClick); buttonGroup.Left = ; buttonGroup.Top = sum; buttonGroup.ItemMeunClick += ButtonGroup_ItemMeunClick; this.pnlMain.Controls.Add(buttonGroup); bgPre = buttonGroup; }
} private void NavClick(object sender,string moduleName)
{
NavButtonClick?.Invoke(sender, moduleName);
} private void ButtonGroup_ItemMeunClick(object sender, EventArgs e)
{
Label lblItem = sender as Label; currentItemIndex = ; if (lblItem != null)
{
ButtonGroup bg = lblItem.Parent as ButtonGroup; if (bg != null)
{
currentItemIndex = Convert.ToInt32(bg.Tag);
} }
ResetMenu();
} private void ResetMenu()
{
if (listGroup != null && listGroup.Count > )
{
int barHeight = ; int totalHeight = pnlMain.Height; for (int n = ; n < listGroup.Count; n++)
{ ButtonGroup buttonGroup = listGroup[n]; int thisIndex = Convert.ToInt32(buttonGroup.Tag); if (thisIndex <= currentItemIndex)
{
buttonGroup.Top =n * barHeight;
}
else
{
buttonGroup.Top = totalHeight - (listGroup.Count-n) * barHeight;
}
if (thisIndex == currentItemIndex)
{
buttonGroup.Height = totalHeight - (listGroup.Count - ) * barHeight;
}
else
{
buttonGroup.Height = barHeight;
}
} }
} #region ButtonGroup
public class ButtonGroup : UserControl
{
private Label lblItem = new Label(); private string text; private Panel ButtonArea = new Panel(); public event EventHandler ItemMeunClick; public event ImageButtonClick ImageButtonClick; public ButtonGroup(string txt,List<ImageButton> listImageButton)
{
this.text = txt;
this._listImageButton = listImageButton; this.Initialize();
} private List<ImageButton> _listImageButton; public List<ImageButton> ListImageButton
{
get { return _listImageButton; }
set { _listImageButton = value; }
} public void Initialize()
{
lblItem.Text = this.text;
lblItem.Height = ;
lblItem.Width = ;
lblItem.TextAlign = ContentAlignment.MiddleCenter;
lblItem.BackColor = Color.DarkGray;
lblItem.ForeColor = Color.DarkRed;
lblItem.Cursor = Cursors.Hand;
lblItem.Click += LblItem_Click; this.Width = ;
this.BackColor = Color.DarkOliveGreen;
this.Controls.Add(lblItem);
this.Controls.Add(ButtonArea);
} private void LblItem_Click(object sender, EventArgs e)
{
ItemMeunClick?.Invoke(sender, e);
} public void SetButtonLocation()
{
ButtonArea.Location = new Point(, ); int buttonCount = _listImageButton == null ? : _listImageButton.Count; int Height = ;
//ButtonArea.BackColor = Color.Red;
ButtonArea.Size = new Size(, buttonCount * Height);
if (_listImageButton != null && _listImageButton.Count > )
{ for (int i = ; i < _listImageButton.Count; i++)
{
var imgButton = _listImageButton[i]; imgButton.Top = i * imgButton.Height;
imgButton.Left = ; imgButton.PictureBoxClick += ImgButton_PictureBoxClick; ButtonArea.Controls.Add(imgButton);
}
} this.Height = lblItem.Height + ButtonArea.Height; } private void ImgButton_PictureBoxClick(object o, string moduleName)
{
ImageButtonClick?.Invoke(o, moduleName);
}
}
#endregion #region ImageButton
public class ImageButton : UserControl
{ private string text; private Image img; private PictureBox picBox=new PictureBox();
private Label lblText = new Label(); public event ImageButtonClick PictureBoxClick; public ImageButton(string txt, Image image)
{
this.text = txt;
this.img = image; this.InitialImageButtonControl();
} public void InitialImageButtonControl()
{ picBox.Size = new Size(, );
picBox.Left = ;
picBox.Top = ;
picBox.Image = this.img;
picBox.Anchor = AnchorStyles.Top;
picBox.SizeMode = PictureBoxSizeMode.StretchImage;
picBox.Cursor = Cursors.Hand;
picBox.Click += new EventHandler(PicBoxClick); lblText.Width = ;
lblText.Height = ;
lblText.Location = new Point(, );
lblText.Text = this.text;
lblText.TextAlign = ContentAlignment.MiddleCenter;
lblText.BackColor = Color.DarkOliveGreen;
lblText.ForeColor = Color.DarkGray;
lblText.Cursor = Cursors.Hand; this.Height = picBox.Height + lblText.Height;
this.Controls.Add(picBox);
this.Controls.Add(lblText);
} private void PicBoxClick(object sender,EventArgs args)
{ PictureBoxClick?.Invoke(sender, this.text);
} }
#endregion }
 

C# Winform 自定义控件——竖着的Navbar的更多相关文章

  1. C# winform 自定义控件

    近来因为项目的问题,开始研究winform自定义控件,这篇主要是将自定义控件的属性在属性编辑器中可编辑,如果你对自定义控件比较了解的,就不用继续往下看了 首先,我创建了一个类UserButton,继承 ...

  2. C#winform自定义控件模拟设计时界面鼠标移动和调节大小、选中效果

    要想玩转Winform自定义控件需要对GDI+非常熟悉,对常用的控件有一些了解,好选择合适的基类控件来简化. 要点说明及代码 1)定义接口: using System; using System.Wi ...

  3. Winform自定义控件实例

    本文转自http://www.cnblogs.com/hahacjh/archive/2010/04/29/1724125.html 写在前面: .Net已经成为许多软件公司的选择,而.Net自定义W ...

  4. winform 自定义控件:半透明Loading控件

    winform  自定义控件:半透明Loading控件 by wgscd date:2015-05-05 效果: using System;using System.Drawing;using Sys ...

  5. c#Winform自定义控件-目录

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  6. (二)c#Winform自定义控件-按钮

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  7. (三)c#Winform自定义控件-有图标的按钮

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  8. (四)c#Winform自定义控件-选择按钮组

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  9. (七)c#Winform自定义控件-进度条

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

随机推荐

  1. 005-python-字典操作

    1. 字典 dict 用{}来表示 键值对数据 {key:value} 唯一性 键 都必须是可哈希的 不可变的数据类型就可以当做字典中的键 值 没有任何限制 dic = {'name':'alex', ...

  2. HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Problem Description   The in ...

  3. Linux虚拟机怎么添加磁盘?

    一.VMware workstation菜单栏

  4. 嵊州D2T2 八月惊魂 全排列 next_permutation()

    嵊州D2T2 八月惊魂 这是一个远古时期的秘密,至今已无人关心. 这个世界的每个时代可以和一个 1 ∼ n 的排列一一对应. 时代越早,所对应的排列字典序就越小. 我们知道,公爵已经是 m 个时代前的 ...

  5. python接口自动化(二十九)--html测试报告通过邮件发出去——上(详解)

    简介 前边几篇,已经教小伙伴们掌握了如何生成HTML的测试报告,那么生成测试报告,我们也不能放在那里不管了,这样即使你报告在漂亮,领导也看不到.因此如果想向领导汇报工作,不仅需要提供更直观的测试报告. ...

  6. 【拓扑排序】排队-C++

    描述 今天,学校老师让同学们排成一队,准备带大家出去玩,一共有 n 名同学,排队的时候同学们向老师提了 m 条要求,每一条要求是说同学 x 一定要排在同学 y 之前,老师现在想找到一种排队方式可以满足 ...

  7. 说说WPF的依赖属性

    首先,我们先来大概了解一下依赖属性 什么是依赖属性:依赖属性自己没有值,通过依赖别人(如Binding)来获得值. 依赖属性为什么会出现:控件常用字段有限,包装太多属性会占用过高内存,造成浪费.所以用 ...

  8. g++ -std=c++11 -g -o test emit_log_direct.cpp

    g++ -std=c++11 -g -o test  emit_log_direct.cpp

  9. 安卓开发之详解getChildFragmentManager和getsupportFragmentManager和getFragmentManager详解

    安卓开发之详解getChildFragmentManager和getsupportFragmentManager和getFragmentManager详解 getFragmentManager()所得 ...

  10. [leetcode] 263. Ugly Number (easy)

    只要存在一种因数分解后,其因子是2,3,5中的一种或多种,就算是ugly数字. 思路: 以2/3/5作为除数除后,最后结果等于1的就是ugly数字 Runtime: 4 ms, faster than ...