DataGridView控件实现行折叠效果

一 重写表格

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace DataGrideViewControl
{
    public class DataGridViewGroupCell : DataGridViewTextBoxCell
    {
        #region Variant

        /// <summary>  
        /// 标示的宽度  
        /// </summary>  
        const int PLUS_WIDTH = 24;

        /// <summary>  
        /// 标示的区域  
        /// </summary>  
        Rectangle groupPlusRect;

        #endregion

        #region Init

        public DataGridViewGroupCell()
        {
            groupLevel = 1;
        }

        #endregion

        #region Property

        int groupLevel;

        /// <summary>  
        /// 组级别(以1开始)  
        /// </summary>  
        public int GroupLevel
        {
            get { return groupLevel; }
            set { groupLevel = value; }
        }

        DataGridViewGroupCell parentCell;

        /// <summary>  
        /// 父节点  
        /// </summary>  
        public DataGridViewGroupCell ParentCell
        {
            get
            {
                return parentCell;
            }
            set
            {
                if (value == null)
                    throw new NullReferenceException("父节点不可为空");
                if (!(value is DataGridViewGroupCell))
                    throw new ArgumentException("父节点必须为 DataGridViewGroupCell 类型");

                parentCell = value;
                parentCell.AddChildCell(this);
            }
        }

        private bool collapsed;

        /// <summary>  
        /// 是否收起  
        /// </summary>  
        public bool Collapsed
        {
            get { return collapsed; }
        }

        private List<DataGridViewGroupCell> childCells = null;

        /// <summary>  
        /// 所有的子结点  
        /// </summary>  
        public DataGridViewGroupCell[] ChildCells
        {
            get
            {
                if (childCells == null)
                    return null;
                return childCells.ToArray();
            }
        }

        /// <summary>  
        /// 取得组标示(有+或-号的框)的区域  
        /// </summary>  
        public Rectangle GroupPlusRect
        {
            get
            {
                return groupPlusRect;
            }
        }

        bool bPaint = true;

        /// <summary>  
        /// 是否重绘  
        /// </summary>  
        public bool BPaint
        {
            get { return bPaint; }
            set { bPaint = value; }
        }

        #endregion

        #region 添加子节点

        /// <summary>  
        /// 添加子结点  
        /// </summary>  
        /// <param name="cell"></param>  
        /// <returns></returns>  
        public int AddChildCell(DataGridViewGroupCell cell)
        {
            return AddChildCellRange(new DataGridViewGroupCell[] { cell });
        }

        public int AddChildCellRange(DataGridViewGroupCell[] cells)
        {
            bool needRedraw = false;
            if (childCells == null)
            {
                //需要画一个加号  
                childCells = new List<DataGridViewGroupCell>();
                needRedraw = true;
            }
            foreach (DataGridViewGroupCell cell in cells)
            {
                childCells.Add(cell);
                cell.groupLevel = groupLevel + 1;
                cell.parentCell = this;
            }

            if (needRedraw)
            {
                DataGridView.InvalidateCell(this);
            }
            return childCells.Count;
        }

        #endregion

        #region 绘制节点

        protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            if (!bPaint)
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                return;
            }
            Pen gridPen = new Pen(DataGridView.GridColor);
            Brush bruBK = new SolidBrush(cellStyle.BackColor);
            int width = groupLevel * PLUS_WIDTH;
            Rectangle rectLeft = new Rectangle(cellBounds.Left, cellBounds.Top - 1, width, cellBounds.Height);
            cellBounds.X += width;
            cellBounds.Width -= width;
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);

            PaintGroupPlus(graphics, gridPen, bruBK, cellStyle, rectLeft, collapsed);

            gridPen.Dispose();
            gridPen = null;

            bruBK.Dispose();
            bruBK = null;
        }

        private void PaintGroupPlus(Graphics graphics, Pen gridPen, Brush bruBK, DataGridViewCellStyle cellStyle, Rectangle rectLeft, bool collapsed)
        {
            Pen pen = new Pen(DataGridView.GridColor, 1);
            pen.DashStyle = DashStyle.Dot;
            graphics.FillRectangle(bruBK, rectLeft);
            int left = rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH;
            //画 Left, Top, Right 三根线  
            graphics.DrawLine(gridPen, left, rectLeft.Top, rectLeft.Right, rectLeft.Top);//上  
            graphics.DrawLine(gridPen, rectLeft.Right, rectLeft.Bottom, rectLeft.Left, rectLeft.Bottom);

            //最左边的一条线  
            graphics.DrawLine(gridPen, rectLeft.Left, rectLeft.Top, rectLeft.Right, rectLeft.Top);

            //如果是该级别的最后一个节点,则需要画一个底线,以便将整个组封闭起来  
            bool drawBottomLine = false;
            for (int i = 1; i < groupLevel; i++)
            {
                if (!ParentCell.IsLastCell(ParentCell.groupLevel))//上层不是最后一个节点  
                {
                    graphics.DrawLine(pen, rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top
                        , rectLeft.Left + (i - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Bottom);
                }
            }

            //如果有子结点, 则需要画一个方框, 里面有+号或-号  
            if (childCells != null && childCells.Count > 0)
            {
                groupPlusRect = new Rectangle((groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 12) / 2
                    , rectLeft.Top + (rectLeft.Height - 12) / 2, 12, 12);
                graphics.DrawRectangle(gridPen, groupPlusRect);

                graphics.DrawLine(Pens.Black, groupPlusRect.Left + 3, groupPlusRect.Top + groupPlusRect.Height / 2
                , groupPlusRect.Right - 3, groupPlusRect.Top + groupPlusRect.Height / 2);
                if (collapsed)
                {
                    graphics.DrawLine(Pens.Black, groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Top + 3
                , groupPlusRect.Left + groupPlusRect.Width / 2, groupPlusRect.Bottom - 3);
                }
            }
            else
            {
                //横  
                graphics.DrawLine(pen, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top + rectLeft.Height / 2
              , rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH, rectLeft.Top + rectLeft.Height / 2);

                //竖  
                if (!IsLastCell((groupLevel - 1)))
                {
                    graphics.DrawLine(pen, rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Top
                        , rectLeft.Left + (groupLevel - 1) * PLUS_WIDTH + PLUS_WIDTH / 2, rectLeft.Bottom);
                }
                else
                    graphics.DrawLine(pen, (groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 8) / 2 + 4, rectLeft.Top + (rectLeft.Height - 8) / 2 - 6,
                        (groupLevel - 1) * PLUS_WIDTH + rectLeft.Left + (PLUS_WIDTH - 8) / 2 + 4, rectLeft.Top + (rectLeft.Height - 8) / 2 + 4);

            }
            pen.Dispose();
            pen = null;
        }

        #endregion

        #region 判断

        /// <summary>  
        /// 该节点是否为某一级节点的最后一个子结点  
        /// </summary>  
        /// <param name="level">节点层级</param>  
        /// <returns></returns>  
        private bool IsLastCell(int level)
        {
            int row = DataGridView.Rows.GetNextRow(RowIndex, DataGridViewElementStates.None);
            if (row == -1)
                return true;
            DataGridViewGroupCell cel = DataGridView.Rows[row].Cells[0] as DataGridViewGroupCell;
            return (cel.GroupLevel == level);
        }

        #endregion

        #region 点击 Cell

        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            Rectangle rect = DataGridView.GetCellDisplayRectangle(ColumnIndex, RowIndex, false);
            Point pt = new Point(rect.Left + e.Location.X, rect.Top + e.Location.Y);
            if (groupPlusRect.Contains(pt))
            {
                if (collapsed)
                {
                    Expand();
                }
                else
                {
                    Collapse();
                }
            }
            base.OnMouseDown(e);
        }

        #endregion

        #region 展开/收起节点

        /// <summary>  
        /// 展开节点  
        /// </summary>  
        public void Expand()
        {
            if (parentCell != null)
            {
                parentCell.CollapseAll();
            }
            collapsed = false;
            ShowChild(true);
            base.DataGridView.InvalidateCell(this);
        }

        private void ShowChild(bool show)
        {
            if (childCells == null)
                return;
            foreach (DataGridViewGroupCell cel in childCells)
            {
                if (cel.RowIndex == -1)
                {
                    continue;
                }

                DataGridView.Rows[cel.RowIndex].Visible = show;
                if (!cel.collapsed)
                    cel.ShowChild(show);
            }
        }

        /// <summary>  
        /// 收起节点  
        /// </summary>  
        public void Collapse()
        {
            collapsed = true;
            ShowChild(false);
            base.DataGridView.InvalidateCell(this);
        }

        /// <summary>  
        /// 展开节点及子结点  
        /// </summary>  
        public void ExpandAll()
        {
            if (childCells == null)
                return;
            foreach (DataGridViewGroupCell cel in childCells)
            {
                cel.ExpandAll();
            }
        }

        public void CollapseAll()
        {
            if (childCells == null)
                return;
            foreach (DataGridViewGroupCell cel in childCells)
            {
                cel.CollapseAll();
            }
        }

        #endregion
    }

    public class DataGridViewGroupColumn : DataGridViewTextBoxColumn
    {
        public DataGridViewGroupColumn()
        {
            CellTemplate = new DataGridViewGroupCell();
            ReadOnly = true;
        }

        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                if ((value != null) && !(value is DataGridViewGroupCell))
                {
                    throw new InvalidCastException("Need System.Windows.Forms.DataGridViewGroupCell");
                }
                base.CellTemplate = value;
            }
        }
    }
    public class DefineDataGridView : DataGridView
    {
        bool showRowHeaderNumbers;
        /// 
        /// 是否显示行号 
        /// 
        /// [Description(“是否显示行号”), DefaultValue(true)]
        public bool ShowRowHeaderNumbers
        {
            get { return showRowHeaderNumbers; }
            set
            {
                if (showRowHeaderNumbers != value)
                    Invalidate();
                showRowHeaderNumbers = value;
            }
        }

        public DefineDataGridView()
        {
            showRowHeaderNumbers = true;
            this.RowHeadersWidth = 30;
            this.AllowUserToAddRows = false;
        }
    }
}

二 应用举例

新建窗体程序
在form中添加datagridviw控件

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

namespace DataGrideViewControl
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //添加重新绘制后可以折叠的列表
            dataGridView1.Columns.Insert(0, new DataGridViewGroupColumn());
            //添加正常的列表
            dataGridView1.Columns.Insert(1, new DataGridViewTextBoxColumn());
            dataGridView1.Columns.Insert(2, new DataGridViewTextBoxColumn());
                  
            DataGridViewGroupCell MainCell = new DataGridViewGroupCell();
            MainCell.Value = "主目录";          
            DataGridViewGroupCell ChildCell1 = new DataGridViewGroupCell();
            ChildCell1.Value = "子目录1";
            DataGridViewGroupCell ChildCell2 = new DataGridViewGroupCell();
            ChildCell2.Value = "子目录2";
              
            Addcolumn(ChildCell2);
            Addcolumn(ChildCell1);
            Addcolumn(MainCell);
            MainCell.AddChildCell(ChildCell1);
            MainCell.AddChildCell(ChildCell2);
        }
        private void Addcolumn(DataGridViewCell Mcell)
        {
            //补充绘制目标单元格
            DataGridViewRow row = new DataGridViewRow();
            row.Cells.Add(Mcell);
            //补充正常单元格作对比
            DataGridViewCell EmptyCell = new DataGridViewTextBoxCell();
            DataGridViewCell EmptyCell2 = new DataGridViewTextBoxCell();
            row.Cells.Add(EmptyCell);
            row.Cells.Add(EmptyCell2);
            dataGridView1.Rows.Insert(0, row);
        }

        private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }
    }
}

结果

在这里插入图片描述
在这里插入图片描述

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值