1. 程式人生 > >C# 模仿Windows可摺疊導航欄

C# 模仿Windows可摺疊導航欄

先上張效果圖,依次為 全展開圖,部分摺疊圖,全部摺疊圖

程式碼下載 



時間倉促,功能相對簡單,也未經過詳細測試,不支援設計期操作,這裡提供思路給大家,有時間完善吧,上程式碼:

程式碼檔案介紹

NavBar.cs                 導航欄主體,繼承自 Panel
NavGroup.cs            NavBar中的分組,即(控制面板,我的電腦等),繼承自Control
NavBarItem.cs        分組中的小項(即區域選項,字型等),繼承自Control
NavBarButton.cs    導航欄主體右邊的圓形按鈕
NavGroupCollection.cs      分組的集合
NavBarItemCollection.cs   分組中小項的集合
NavGroupState.cs  組的狀態,收縮還是展開



NavBar.cs

using System;
using System.Collections.Generic;
using System.Drawing.Design;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class NavBar : Panel
    {
        private NavGroupCollection _groups;
        public NavGroupCollection Groups
        {
            get { return this._groups; }
        }
        public NavGroup this[int index]
        {
            get
            {
                if (index > -1)
                    return this._groups[index];
                else
                    return null;
            }
        }
        private int _selectedIndex = -1;
        /// <summary>
        /// 選擇組的索引
        /// </summary>
        [DefaultValue(-1)]
        public int SelectedIndex
        {
            get { return this._selectedIndex; }
            set 
            { 
                this._selectedIndex = value;
                this.SelectGroup(value);
            }
        }
        private int _groupSpace = 20;
        /// <summary>
        /// Group間距
        /// </summary>
        public int GroupSpace
        {
            get { return this._groupSpace; }
            set { this._groupSpace = value; }
        }
        private int _groupMargin = 5;
        /// <summary>
        /// Group邊距
        /// </summary>
        public int GroupMargin
        {
            get { return this._groupMargin; }
            set { this._groupMargin = value; }
        }
        private ImageList _smallImageList;
        /// <summary>
        /// 設定影象列表
        /// </summary>
        public ImageList SmallImageList
        {
            get { return this._smallImageList; }
            set { this._smallImageList = value; }
        }
        public NavBar()
        {
            InitializeComponent();
            
            this.BackColor = Color.FromArgb(112, 140, 225);
            this._groups = new NavGroupCollection(this);
            this.AutoScroll = true;
        }
        /// <summary>
        /// 根據新增的項,佈局
        /// </summary>
        /// <param name="item"></param>
        public void SetLayOut(NavGroup item)
        {
            this.SuspendLayout();
            this.Controls.Add(item);
            if (this._groups.Count == 0)
            {
                item.Top = 10;
            }
            else
            {
                item.Top = this[this._groups.Count - 1].Bottom + this.GroupSpace;
            }
            item.Width = this.Width - 2 * this.GroupMargin;
            item.Left = (this.Width - item.Width) / 2;
            item.Height = item.TitleHeight;
            this.ResumeLayout();
            //item.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
        }
        /// <summary>
        /// 重新佈局元件
        /// </summary>
        public void SetLayOut()
        {
            for (int i = 0; i < this._groups.Count; i++)
            {
                if (i == 0)
                    this._groups[i].Top = 10;
                else
                {
                    this._groups[i].Top = this._groups[i - 1].Bottom + this._groupSpace;
                    this._groups[i].GroupIndex = i;
                }
            }
        }
        /// <summary>
        /// 新增分組
        /// </summary>
        /// <returns></returns>
        public NavGroup AddGroup()
        {
            this._groups.Add();
            return this._groups[this._groups.Count - 1];
        }
        /// <summary>
        /// 刪除分組
        /// </summary>
        /// <param name="item"></param>
        public void RemoveGroup(NavGroup item)
        {
            int i = item.GroupIndex;
            this._groups.Remove(item);
            this.Controls.Remove(item);
            this.SetLayOut();
        }
        /// <summary>
        /// 刪除指定索引的分組
        /// </summary>
        /// <param name="index"></param>
        public void RemoveGroupAt(int index)
        {
            this.Controls.Remove(this._groups[index]);
            this._groups.RemoveAt(index);            
            this.SetLayOut();
        }
        /// <summary>
        /// 選中指定索引的分組
        /// </summary>
        /// <param name="index"></param>
        private void SelectGroup(int index)
        {
            foreach (NavGroup g in this._groups)
            {
                if (g.GroupIndex == this._selectedIndex) continue;
                g.IsSelected = false;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
        }
    }
}

NavGroup.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public partial class NavGroup : Control
    {
        private Rectangle _titleRectangle;
        private NavBar _ownerBar;
        private NavBarButton _button;
        private NavBarItemCollection _items;
        public NavBarItemCollection Items
        {
            get { return this._items; }
            set { this._items = value; }
        }
        public NavBarItem this[int index]
        {
            get
            {
                if (index > -1)
                    return this._items[index];
                else
                    return null;
            }
        }
        private NavGroupState _groupState = NavGroupState.expand;
        /// <summary>
        /// 組的狀態
        /// </summary>
        public NavGroupState GroupState
        {
            get { return this._groupState; }
            set 
            { 
                this._groupState = value;
                this.SetGroupState(value);
            }
        }
        private int _groupIndex;
        /// <summary>
        /// 組索引
        /// </summary>
        public int GroupIndex
        {
            get { return this._groupIndex; }
            set { this._groupIndex = value; }
        }
        private int _titleHeight = 20;
        /// <summary>
        /// 標題高度
        /// </summary>
        public int TitleHeight
        {
            get { return this._titleHeight; }
            set
            {
                this._titleHeight = value;
                this.SetTitleRectangle();
            }
        }
        private string _title;
        /// <summary>
        /// 標題
        /// </summary>
        public string Title
        {
            get { return this._title; }
            set { this._title = value; }
        }
        private Color _titleStartColor = Color.White;
        /// <summary>
        /// 標題漸變開始色
        /// </summary>
        public Color TitleStartColor
        {
            get { return this._titleStartColor; }
            set
            {
                this._titleStartColor = value;
            }
        }
        private Color _titleEndColor = Color.FromArgb(199, 211, 247);
        /// <summary>
        /// 標題漸變結束色
        /// </summary>
        public Color TitleEndColor
        {
            get { return this._titleEndColor; }
            set
            {
                this._titleEndColor = value;
            }
        }
        private int _itemSpace = 5;
        /// <summary>
        /// Item間距
        /// </summary>
        public int ItempSpace
        {
            get { return this._itemSpace; }
            set { this._itemSpace = value; }
        }
        private int _itemMargin = 5;
        /// <summary>
        /// Item邊距
        /// </summary>
        public int ItemMargin
        {
            get { return this._itemMargin; }
            set { this._itemMargin = value; }
        }
        private bool _isSelected = false;
        /// <summary>
        /// 是否選中
        /// </summary>
        public bool IsSelected
        {
            get { return this._isSelected; }
            set 
            { 
                this._isSelected = value;
                this.Invalidate();
            }
        }
        private ImageList _smallImageList;
        public ImageList SmallImageList
        {
            get { return this._smallImageList; }
            set { this._smallImageList = value; }
        }

        public NavGroup()
        {
            InitializeComponent();
            this._title = "新建組";
            this.BackColor = Color.FromArgb(214,223,247);
            SetTitleRectangle();
            this._button = new NavBarButton(this);
            this._button.Click += new EventHandler
                (
                delegate(object sender, EventArgs e)
                {
                    if (this._groupState == NavGroupState.collapse)
                        this.GroupState = NavGroupState.expand;
                    else
                        this.GroupState = NavGroupState.collapse;
                });
            this._items = new NavBarItemCollection(this);
        }
        public NavGroup(NavBar ownerbar):this()
        {
            this._ownerBar = ownerbar;
        }
        /// <summary>
        /// 設定標題區域
        /// </summary>
        private void SetTitleRectangle()
        {
            this._titleRectangle = new Rectangle(0, 0, this.Width, _titleHeight);
        }
        /// <summary>
        /// 新增專案
        /// </summary>
        /// <returns></returns>
        public NavBarItem AddItem()
        {
            this._items.Add();
            return this._items[this._items.Count - 1];
        }
        /// <summary>
        /// 設定組狀態
        /// </summary>
        /// <param name="value"></param>
        private void SetGroupState(NavGroupState value)
        {
            if (value == NavGroupState.collapse)
            {
                this.Height = this._titleHeight;
            }
            else
            {
                if (this._items.Count > 0)
                {
                    this.Height = this._items[this._items.Count - 1].Bottom + this._itemSpace;
                }
            }
            this._ownerBar.SetLayOut();
        }
        /// <summary>
        /// 根據新增項佈局
        /// </summary>
        /// <param name="item"></param>
        public void SetLayOut(NavBarItem item)
        {
            this.SuspendLayout();
            this.Controls.Add(item);
            if (this._items.Count == 0)
            {
                item.Top = this._titleHeight + 10;
            }
            else
            {
                item.Top = this[this._items.Count - 1].Bottom + this.ItempSpace;
            }
            item.Width = this.Width - 2 * this.ItemMargin;
            item.Left = (this.Width - item.Width) / 2;
            this.Height = item.Bottom + this.ItempSpace;
            this._ownerBar.SetLayOut();
            this.ResumeLayout();
        }
        /// <summary>
        /// 重新佈局,這個需要完善
        /// </summary>
        /// <param name="index"></param>
        public void SetLayOut(int index)
        {
            for (int i = index + 1; i < this._items.Count; i++)
            {
                this._items[i].Top = this._items[i-1].Bottom + this._itemSpace;
            }
        }

        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);
            this.IsSelected = true;
            this._ownerBar.SelectedIndex = this._groupIndex;
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (this._button.ClientRectangle.Contains(e.Location))
            {
                this._button.DoClick();
                this.Invalidate();
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            SizeF size = e.Graphics.MeasureString(this._title, this.Font);
            Font titlefont = new Font(this.Font.FontFamily,this.Font.Size, this.Font.Style | FontStyle.Bold);
            //未選中
            if (!this._isSelected)
            {
                LinearGradientBrush brush = new LinearGradientBrush(this._titleRectangle, this._titleStartColor, this._titleEndColor, 0f);
                e.Graphics.FillRectangle(brush, this._titleRectangle);
                e.Graphics.DrawString(this._title, titlefont, Brushes.Black, this._titleRectangle.X, this._titleRectangle.Top + (this._titleRectangle.Height - size.Height) / 2);
            }
            else
            {
                e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(35, 90, 200)), this._titleRectangle);
                e.Graphics.DrawString(this._title, titlefont, Brushes.White, this._titleRectangle.X, this._titleRectangle.Top + (this._titleRectangle.Height - size.Height) / 2);
            }
            e.Graphics.DrawRectangle(Pens.White, new Rectangle(0, 0, this.Width - 1, this.Height - 1));
            //繪製右側原型按鈕
            this._button.Draw(e.Graphics);
            
        }
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            SetTitleRectangle();
            this._button.SetClientRectangle(this._titleRectangle);
        }
    }
}

NavBarItem.cs,這裡偷了個懶,該元件包含一個PictureBox和Label元件,PictureBox用來顯示圖示,Lable用來顯示文字
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsApplication1
{
    public partial class NavBarItem : Control
    {
        /// <summary>
        /// 供外部呼叫項的點選事件
        /// </summary>
        [Browsable(false)]
        public event EventHandler ItemClick;

        private Rectangle _imageRectangle;
        private PictureBox _picbox;
        private Label _titlebox;

        private NavGroup _ownerGroup;
        /// <summary>
        /// 所屬組
        /// </summary>
        public NavGroup OwnerGroup
        {
            get { return this._ownerGroup; }
            set { this._ownerGroup = value; }
        }
        private int _itemIndex;
        public int ItemIndex
        {
            get { return this._itemIndex; }
            set { this._itemIndex = value; }
        }
        private int _imageIndex = -1;
        /// <summary>
        /// 圖示的索引
        /// </summary>
        public int ImageIndex
        {
            get { return this._imageIndex; }
            set
            {
                if (this._ownerGroup.SmallImageList == null) return;
                if (value >= this._ownerGroup.SmallImageList.Images.Count) return;
                this._imageIndex = value;
                this._picbox.Image = this._ownerGroup.SmallImageList.Images[this._imageIndex];
                this.Invalidate();
            }
        }
        private new string _text;
        /// <summary>
        /// 設定顯示文字
        /// </summary>
        public new string Text
        {
            get { return this._text; }
            set
            {
                this._text = value;
                this._titlebox.Text = value;
                this.Invalidate();
            }
        }
        public NavBarItem()
        {
            InitializeComponent();
            this.AutoSize = false;
            this.Height = 22;
            this.Cursor = Cursors.Hand;
            this._titlebox = new Label();
            this._titlebox.Parent = this;
            this._titlebox.Dock = DockStyle.Fill;
            this._titlebox.TextAlign = ContentAlignment.MiddleLeft;
            this._titlebox.MouseHover += new EventHandler(this.OnTitleMouseHover);
            this._titlebox.MouseLeave += new EventHandler(this.OnTitleMouseLeave);
            this._titlebox.Click += new EventHandler(this.OnTitleClick);
            this._picbox = new PictureBox();
            this._picbox.Parent = this;
            this._picbox.Dock = DockStyle.Left;
            this._picbox.Width = this.Height;
            this._picbox.SizeMode = PictureBoxSizeMode.CenterImage;
            this.Text = "新建專案";
        }
        public NavBarItem(NavGroup ownergroup)
            : this()
        {
            this._ownerGroup = ownergroup;
        }

        private void OnTitleClick(object sender, EventArgs e)
        {
            base.OnClick(e);
            if (this.ItemClick != null)
            {
                this.ItemClick(this, new EventArgs());
            }
        }
        private void OnTitleMouseHover(object sender,EventArgs e)
        {
            Control c = (Control)sender;
            c.ForeColor = Color.Blue;
            c.Font = new Font(c.Font.FontFamily, c.Font.Size, c.Font.Style | FontStyle.Underline);
        }
        private void OnTitleMouseLeave(object sender, EventArgs e)
        {
            Control c = (Control)sender;
            c.ForeColor = SystemColors.ControlText;
            c.Font = new Font(c.Font.FontFamily, c.Font.Size, FontStyle.Regular);
        }
    }
}

NavBarButton.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace WindowsApplication1
{
    public class NavBarButton
    {
        private NavGroup _navgroup;
        private Rectangle _clientRectangle;
        public Rectangle ClientRectangle
        {
            get { return this._clientRectangle; }
            set { this._clientRectangle = value; }
        }

        public NavBarButton() { }
        public NavBarButton(NavGroup navgroup)
        {
            this._navgroup = navgroup;
        }

        public event EventHandler Click;

        public void SetClientRectangle(Rectangle parentRect)
        {
            int i =2;
            int w = parentRect.Height;
            this._clientRectangle = new Rectangle(parentRect.Width - w + i, parentRect.Top + i, w - 2 * i, w - 2 * i);
        }
        public void Draw(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillEllipse(Brushes.White, this._clientRectangle);
            g.DrawEllipse(Pens.Gray, this._clientRectangle);
            Point centerpoint = new Point(this._clientRectangle.X + this._clientRectangle.Width / 2, this._clientRectangle.Y + this._clientRectangle.Height / 2);
            int w = this._clientRectangle.Width / 4;
            Pen pen = new Pen(Color.Black, 1.6f);
            if (this._navgroup.GroupState == NavGroupState.collapse)
            {
                g.DrawLine(pen, centerpoint.X, centerpoint.Y, centerpoint.X - w, centerpoint.Y - w);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y, centerpoint.X + w, centerpoint.Y - w);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y + 4, centerpoint.X - w, centerpoint.Y + w - 4);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y + 4, centerpoint.X + w, centerpoint.Y + w - 4);
            }
            else
            {
                g.DrawLine(pen, centerpoint.X, centerpoint.Y, centerpoint.X - w, centerpoint.Y + w);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y, centerpoint.X + w, centerpoint.Y + w);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y - 4, centerpoint.X - w, centerpoint.Y + w - 4);
                g.DrawLine(pen, centerpoint.X, centerpoint.Y - 4, centerpoint.X + w, centerpoint.Y + w - 4);
            }
        }
        public void DoClick()
        {
            if (this.Click != null)
            {
                this.Click(this, new EventArgs());
            }
        }
    }
}

NavGroupCollection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsApplication1
{
    public class NavGroupCollection :List<NavGroup>
    {
        private NavBar _ownerBar;
        public NavGroupCollection(NavBar ownerBar):base()
        {
            this._ownerBar = ownerBar;
        }
        public new void Add(NavGroup item)
        {
            this._ownerBar.SetLayOut(item);
            base.Add(item);
            item.GroupIndex = this.Count - 1;
            item.SmallImageList = this._ownerBar.SmallImageList;
        }
        public new void Add()
        {
            NavGroup item = new NavGroup(this._ownerBar);
            this.Add(item);
        }

    }
}

NavBarItemCollection.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsApplication1
{
    public class NavBarItemCollection : List<NavBarItem>
    {
        private NavGroup _ownerGroup;
        
        public NavBarItemCollection(NavGroup ownerGroup):base()
        {
            this._ownerGroup = ownerGroup;
        }
        public new void Add(NavBarItem item)
        {
            this._ownerGroup.SetLayOut(item);
            base.Add(item);
            item.ItemIndex = this.Count - 1;
        }
        public new void Add()
        {
            NavBarItem item = new NavBarItem(this._ownerGroup);
            this.Add(item);            
        }
    }
}

NavGroupState.cs
using System;

namespace WindowsApplication1
{
    public enum NavGroupState
    {
        expand,
        collapse
    }
}

使用,按鈕點選時,寫如下程式碼

            NavBarItem item;
            navBar1.AddGroup().Title = "控制面板";
            item = navBar1[0].AddItem();
            item.ImageIndex = 0;
            item.Text = "區域選項";
            item = navBar1[0].AddItem();
            item.ImageIndex = 1;
            item.Text = "字型";
            item = navBar1[0].AddItem();
            item.ImageIndex = 2;
            item.Text = "新增硬體";
            navBar1.AddGroup().Title = "我的電腦";
            item = navBar1[1].AddItem();
            item.ImageIndex = 3;
            item.Text = "C 盤";
            navBar1.AddGroup().Title = "網路上的芳鄰";
            item = navBar1[2].AddItem();
            item.ImageIndex = 4;
            item.Text = "本地連線";
            item = navBar1[2].AddItem();
            item.ImageIndex = 5;
            item.Text = "VPN連線";
            navBar1.AddGroup().Title = "我的文件";  
            item = navBar1[3].AddItem();
            item.ImageIndex = 6;
            item.Text = "文件 A";
            item = navBar1[3].AddItem();
            item.ImageIndex = 7;
            item.Text = "文件 B";
            item = navBar1[3].AddItem();
            item.ImageIndex = 8;
            item.Text = "文件 C";