业余学过几年FoxPro,从未接触过C#,这几天心血来潮,想在C#中做一个抽屉式导航菜单,却被控件的Dock属性搞得晕头转向,经过一番摸索后终于成功了。当然,这只是一个雏形,新手可以看一下,也请各位高手莫笑话,并能提出改进意见,谢谢!
一、准备工作:
1、一个panel控件,命名为panel1;
2、若干button控件,分别命名为button1,button2, button3.....,高度全部为25(
重要!一定要设成同样的高度!),TabIndex属性分别为0,1,2,3(
非常重要!一定要从0开始按顺序递增,至于为什么,后面你自然明白),调整布局,如图一:
3、打开窗体的Designer.cs,从上至下修改为你想要的顺序,如button1,button2, button3,.....以此类推(
非常重要!从上至下的顺序要与图一的布局完全一致,不能颠倒,至于为什么,你研究一下控件的Dock属性就明白了),如图二:

二、在button控件Click事件中写下以下代码:
int myHeight = 25;//假设Button高度为25,可自行定义,但要求全部同高
int myIndex = this.panel1.Controls.IndexOf((Button)sender);//获取当前控件索引
foreach (Control myButton in this.panel1.Controls)//遍历所有控件
{
if (myButton.TabIndex <= myIndex)
{
myButton.Dock = DockStyle.None;//先清除Dock属性(这一步很重要)
myButton.Top = myButton.TabIndex * myHeight;//重新定义Top值
}
else
{
myButton.Dock = DockStyle.Bottom;//设置Dock属性:置底
}
}
大概这样子吧
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Test_1
{
public partial class Form1 : Form
{
private int select_num = 0;
public class Drawer
{
public string btn_text;
public int btn_height;
public int content_height;
public Control control; // 里面放置组件
public Drawer(string text,int bh, int ch,Control cl)
{
btn_text = text;
btn_height = bh;
content_height = ch;
control = cl;
}
}
public static List<Drawer> drawers = new List<Drawer>();
public void DrawerMenu(Control parent, Point point, BorderStyle borderStyle, Color bcolor, Size size )
{
Panel panel_box = new Panel() { Size = size, BackColor = bcolor };
for (int i= drawers.Count-1; i>-1;i--)
{
Panel panel_control = new Panel() { Dock = DockStyle.Top, Name = "window_" + i, BackColor = Color.SteelBlue };
panel_box.Controls.Add(panel_control);
if (i == 0) panel_control.Visible = true;
else panel_control.Visible = false;
panel_control.Controls.Add(drawers[i].control);
Button button = new Button() { Dock = DockStyle.Top, Height = drawers[i].btn_height,Text = drawers[i].btn_text,Tag = i };
button.Click += Button_Click;
panel_box.Controls.Add(button);
}
parent.Controls.Add(panel_box);
}
private void Button_Click(object sender, EventArgs e)
{
Control pL = (Control)sender;
if (select_num != (int)pL.Tag)
{
pL.Parent.Controls["window_" + select_num].Visible = false;
pL.Parent.Controls["window_" + (int)pL.Tag].Visible = true;
select_num = (int)pL.Tag;
}
}
public Form1()
{
InitializeComponent();
drawers.Add(new Drawer("Button_1",25,35,null));
drawers.Add(new Drawer("Button_2", 25, 35, null));
drawers.Add(new Drawer("Button_3", 25, 35, null));
drawers.Add(new Drawer("Button_4", 25, 35, null));
DrawerMenu(this, new Point(30,30), BorderStyle.FixedSingle, Color.White, new Size(200, 300));
}
}
}
朋友,任何高手都是从菜鸟过来的,没有人天生就懂!我才学了3天C#,又是业余的,自然没你们功底好。真正的高手从来都是谦虚的,你永远不知道明天或者后天,以前让你看不上眼的菜鸟会甩你几条街!如果你觉得那段代码不好,你完全可以写个更好给大家分享一下啊。
谢谢两位支持!其实我个人觉得那几行代码还是可行的。这几天我看了许多网友为了实现类似的效果,有的代码很多,有的用了第三方控件。期待有大腕能用更简单、高效的方法放出来让我们这些新人学习一下。
https://www.haolizi.net/example/view_7669.html 给你推荐一个
老实讲,以实际操作来说,用tree 当导航控件比较好操作
因为,一点全部可操作的FORM 都出来了
你来分享技术或者讨论都挺好的,来说些废话硬当shax那就给爷爪巴
鼓励一下自己开发自定义控件的做法,不过如果商用推荐使用现成控件,devpress,或componentone,不要自己造轮子
我觉得还有优化的空间,特别是在新加入控件后,tabindex也会增加索引,此时排序就会出错。建议在每个按钮事件循环遍历的时候增加个判断,只循环Button控件的索引。另外,控件高度可以直接获得,不用写死。这样方便后续更改。其中某个按钮事件代码如下:
int myHeight = ((Button)sender).Height;//假设Button高度为25,可自行定义,但要求全部同高
int myIndex = this.panel1.Controls.IndexOf((Button)sender);//获取当前控件索引
foreach (Control myButton in this.panel1.Controls)//遍历所有控件
{
if (myButton is Button )
{
if (myButton.TabIndex <= myIndex)
{
myButton.Dock = DockStyle.None;//先清除Dock属性(这一步很重要)
myButton.Top = myButton.TabIndex * myHeight;//重新定义Top值
}
else
{
myButton.Dock = DockStyle.Bottom;//设置Dock属性:置底
}
}
else
{
pictureBox1.Dock = DockStyle.None;
pictureBox1.Top = ((Button)sender).Height + ((Button)sender).Top;
}
}
给楼主个思路,之前写的,就是自己选图片,利用pannel,pictureBox,label然后根据方法组中的按钮信息自动生成,点击展开和关闭的时候计算坐标是相对麻烦(思路清晰就很好算),还有就是初始坐标要获取form 的坐标
我直接使用Devexpress菜单,非常好用,样式也多

看看我的软件
可能用dev控件是最方便的。
或者考虑用wpf实现。