1. 程式人生 > 實用技巧 >自繪 TreeDataView 控制元件

自繪 TreeDataView 控制元件

自定義TreeDataView 控制元件,百萬級別資料秒繪。

最近需要使用到資料展現,需要對資料摺疊展現。網上找了許多控制元件,如:TreeListView,TreevDataGirdView等,但是都無法到達效果,而且載入百萬條資料時,繪製灰常的卡頓。

話不多說。先上效果圖

1 準備工作,建立兩個類,使用者繪製行與列

  public class UserRow
    {
        /// <summary>
        /// 建構函式
        /// </summary>
        /// <param name="level">節點等級</param>
public UserRow(int level) { _level = level; strFmt.Alignment = StringAlignment.Near; //文字水平居中 strFmt.LineAlignment = StringAlignment.Center; //文字垂直居中 } int _level = 0; public int Level { get { return _level; } }
public UserRow Parent { get; set; } = null; public float PointX = 0; public float PointY = 0; //public float RowHeigth = 20; public bool ExpandEvent = false; private bool _expand = false; public bool Expand { get { return _expand; }
set { _expand = value; } } private float _marginLeft = 30; public float MarginLeft { get { return _marginLeft; } } public bool IsSelected = false; public List<UserCell> Cells = new List<UserCell>(); List<UserRow> _subrows = new List<UserRow>(); public List<UserRow> SubRows { get { return _subrows; } } StringFormat strFmt = new System.Drawing.StringFormat(); Font myFont = new Font("宋體", 10); public float Draw(Graphics g, float dx, float dy, float MapLocationX, float MapLocationY, float h, float w, List<UserCell> colums) { PointY = dy; float margleft = calcMarginLeft(this); float x = PointX - MapLocationX ; float y = PointY - MapLocationY; if (_level == 0) { g.FillRectangle(Brushes.LightSkyBlue, x, y + 1, w - 2, h - 1); } else { g.FillRectangle(Brushes.White, x, y + 1, w - 2, h - 1); } if (this.SubRows.Count > 0) { RectangleF plusRect = new RectangleF(x + margleft - 15, y + 5, 10, 10);// +-號的大小 是9 * 9 g.FillRectangle(Brushes.White, plusRect); g.DrawRectangle(new Pen(Brushes.Black), plusRect.X, plusRect.Y, plusRect.Width, plusRect.Height); if (this.Expand) { g.DrawString("-", new Font("宋體", 9), Brushes.Black, plusRect); } else { g.DrawString("+", new Font("宋體", 9), Brushes.Black, plusRect); } } float startPointX = x + margleft ; for (int i = 0; i < colums.Count; i++) { if (colums[i].IsViszble && i< Cells.Count) { RectangleF rf = new RectangleF(startPointX, y + 1, colums[i].Width, h - 1); if (colums[i].IsSelect) { g.FillRectangle(Brushes.Black, rf); g.DrawString(Cells[i].Value, myFont, Brushes.White, rf, strFmt); } else { g.FillRectangle(Brushes.Transparent, rf); g.DrawString(Cells[i].Value, myFont, Brushes.Black, rf, strFmt); } //g.DrawLine(new Pen(Brushes.White, 1), startPointX, y, startPointX, y + h); startPointX += colums[i].Width; } } Pen mypen; if (IsSelected) { mypen = new Pen(Brushes.Red, 1); g.DrawRectangle(mypen, x, y + 1, w -2, h - 1); } else { mypen = new Pen(Brushes.White, 1); g.DrawRectangle(mypen, x, y + 1,w -2, h - 1); } return startPointX + margleft; } public float CalcMaxWidth() { float width = PointX; float margleft = calcMarginLeft(this); for (int i = 0; i < Cells.Count; i++) { width += Cells[i].Width; } return width + margleft; } public float calcMarginLeft(UserRow row) { return (row.Level + 1) * row.MarginLeft; //if (row.Parent != null) //{ // float t = calcMarginLeft(row.Parent); // return row.Parent.MarginLeft + t; //} //else //{ // return row.MarginLeft; //} } public bool IsSelect(float dx, float dy, float h, float w) { float margleft = calcMarginLeft(this); ExpandEvent = false; if (dx <= PointX + w && dx >= PointX && dy <= PointY + h && dy >= PointY) { IsSelected = true; RectangleF plusRect = new RectangleF(PointX + margleft - 15, PointY + 5, 10, 10);// +-號的大小 是9 * 9 if (dx <= plusRect.X + plusRect.Width && dx >= plusRect.X && dy <= plusRect.Y + plusRect.Height && dy >= plusRect.Y) { _expand = !_expand; ExpandEvent = true; } } else { IsSelected = false; } return IsSelected; } } public class UserCell { /// <summary> /// 當前值 /// </summary> public string Value { get; set; } /// <summary> /// 預設單元格寬度 /// </summary> public float Width { get; set; } = 80; /// <summary> /// 是否顯示 /// </summary> public bool IsViszble { get; set; } = true; /// <summary> /// 是否選中單元格 /// </summary> public bool IsSelect { get; set; } = false; }

2 新增使用者控制元件,然後在控制元件上面新增 三個控制元件,PictureBox,vScrollBar1,hScrollBar1

PictureBox 用於繪製資料,vScrollBar1,hScrollBar1用於移動資料

設計程式碼

namespace UserTreeTable
{
    partial class UserControl1
    {
        /// <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.components = new System.ComponentModel.Container();
            this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
            this.hScrollBar1 = new System.Windows.Forms.HScrollBar();
            this.pbImg = new System.Windows.Forms.PictureBox();
            this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
            this.摺疊ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.摺疊層一ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.摺疊層二ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.展開ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.展開層一ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            this.展開層二ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
            ((System.ComponentModel.ISupportInitialize)(this.pbImg)).BeginInit();
            this.contextMenuStrip1.SuspendLayout();
            this.SuspendLayout();
            // 
            // vScrollBar1
            // 
            this.vScrollBar1.Dock = System.Windows.Forms.DockStyle.Right;
            this.vScrollBar1.Location = new System.Drawing.Point(439, 0);
            this.vScrollBar1.Name = "vScrollBar1";
            this.vScrollBar1.Size = new System.Drawing.Size(17, 325);
            this.vScrollBar1.TabIndex = 0;
            this.vScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.vScrollBar1_Scroll);
            this.vScrollBar1.ValueChanged += new System.EventHandler(this.vScrollBar1_ValueChanged);
            // 
            // hScrollBar1
            // 
            this.hScrollBar1.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.hScrollBar1.Location = new System.Drawing.Point(0, 308);
            this.hScrollBar1.Name = "hScrollBar1";
            this.hScrollBar1.Size = new System.Drawing.Size(439, 17);
            this.hScrollBar1.TabIndex = 1;
            this.hScrollBar1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.hScrollBar1_Scroll);
            this.hScrollBar1.ValueChanged += new System.EventHandler(this.hScrollBar1_ValueChanged);
            // 
            // pbImg
            // 
            this.pbImg.BackColor = System.Drawing.SystemColors.Control;
            this.pbImg.ContextMenuStrip = this.contextMenuStrip1;
            this.pbImg.Dock = System.Windows.Forms.DockStyle.Fill;
            this.pbImg.Location = new System.Drawing.Point(0, 0);
            this.pbImg.Name = "pbImg";
            this.pbImg.Size = new System.Drawing.Size(439, 308);
            this.pbImg.TabIndex = 2;
            this.pbImg.TabStop = false;
            this.pbImg.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
            this.pbImg.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
            this.pbImg.Resize += new System.EventHandler(this.pbImg_Resize);
            // 
            // contextMenuStrip1
            // 
            this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.摺疊ToolStripMenuItem,
            this.展開ToolStripMenuItem});
            this.contextMenuStrip1.Name = "contextMenuStrip1";
            this.contextMenuStrip1.Size = new System.Drawing.Size(153, 70);
            // 
            // 摺疊ToolStripMenuItem
            // 
            this.摺疊ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.摺疊層一ToolStripMenuItem,
            this.摺疊層二ToolStripMenuItem});
            this.摺疊ToolStripMenuItem.Name = "摺疊ToolStripMenuItem";
            this.摺疊ToolStripMenuItem.Size = new System.Drawing.Size(100, 22);
            this.摺疊ToolStripMenuItem.Text = "摺疊";
            // 
            // 摺疊層一ToolStripMenuItem
            // 
            this.摺疊層一ToolStripMenuItem.Name = "摺疊層一ToolStripMenuItem";
            this.摺疊層一ToolStripMenuItem.Size = new System.Drawing.Size(124, 22);
            this.摺疊層一ToolStripMenuItem.Text = "摺疊層一";
            this.摺疊層一ToolStripMenuItem.Click += new System.EventHandler(this.摺疊層一ToolStripMenuItem_Click);
            // 
            // 摺疊層二ToolStripMenuItem
            // 
            this.摺疊層二ToolStripMenuItem.Name = "摺疊層二ToolStripMenuItem";
            this.摺疊層二ToolStripMenuItem.Size = new System.Drawing.Size(124, 22);
            this.摺疊層二ToolStripMenuItem.Text = "摺疊層二";
            this.摺疊層二ToolStripMenuItem.Click += new System.EventHandler(this.摺疊層二ToolStripMenuItem_Click);
            // 
            // 展開ToolStripMenuItem
            // 
            this.展開ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.展開層一ToolStripMenuItem,
            this.展開層二ToolStripMenuItem});
            this.展開ToolStripMenuItem.Name = "展開ToolStripMenuItem";
            this.展開ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.展開ToolStripMenuItem.Text = "展開";
            // 
            // 展開層一ToolStripMenuItem
            // 
            this.展開層一ToolStripMenuItem.Name = "展開層一ToolStripMenuItem";
            this.展開層一ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.展開層一ToolStripMenuItem.Text = "展開層一";
            this.展開層一ToolStripMenuItem.Click += new System.EventHandler(this.展開層一ToolStripMenuItem_Click);
            // 
            // 展開層二ToolStripMenuItem
            // 
            this.展開層二ToolStripMenuItem.Name = "展開層二ToolStripMenuItem";
            this.展開層二ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.展開層二ToolStripMenuItem.Text = "展開層二";
            this.展開層二ToolStripMenuItem.Click += new System.EventHandler(this.展開層二ToolStripMenuItem_Click);
            // 
            // UserControl1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.pbImg);
            this.Controls.Add(this.hScrollBar1);
            this.Controls.Add(this.vScrollBar1);
            this.Name = "UserControl1";
            this.Size = new System.Drawing.Size(456, 325);
            this.Resize += new System.EventHandler(this.UserControl1_Resize);
            ((System.ComponentModel.ISupportInitialize)(this.pbImg)).EndInit();
            this.contextMenuStrip1.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.VScrollBar vScrollBar1;
        private System.Windows.Forms.HScrollBar hScrollBar1;
        private System.Windows.Forms.PictureBox pbImg;
        private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
        private System.Windows.Forms.ToolStripMenuItem 摺疊ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 摺疊層一ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 摺疊層二ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 展開ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 展開層一ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 展開層二ToolStripMenuItem;
    }
}

3 在自定義控制元件UserControl1中實現繪製

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

namespace UserTreeTable
{
    public partial class UserControl1 : UserControl
    {
        public UserControl1(List<UserRow> rows)
        {
            InitializeComponent();

            this.Load += UserControl1_Load;
            this.pbImg.MouseWheel += PbImg_MouseWheel;
            Rows = rows;
        }

       /// <summary>
       /// 所有行
       /// </summary>
        public List<UserRow> Rows = new List<UserRow>();

        /// <summary>
        /// 所有列
        /// </summary>
        public SortedList<int, UserRow> HeadColumns = new SortedList<int, UserRow>();

        /// <summary>
        /// 選中的列
        /// </summary>
        List<UserCell> selectHeadColumns = new List<UserCell>();


        /// <summary>
        /// 選中行
        /// </summary>
        UserRow _selectRow;

        /// <summary>
        /// 影象平移後橫座標偏移的畫素
        /// </summary>
        public float MapLocationX = 0;
        /// <summary>
        ///  影象平移後縱座標偏移的畫素
        /// </summary>
        public float MapLocationY = 0;

        /// <summary>
        /// 固定行號
        /// </summary>
        const int rowHeight = 20;
        /// <summary>
        /// 預設行寬
        /// </summary>
        float rowWidth = 100;

        //float MaxHeight = 0;
        //float MaxWidth = 0;

        private void UserControl1_Load(object sender, EventArgs e)
        {
            CalcMapSize();
            if (Rows.Count > 0)
                _selectRow = Rows[0];
        }

        private void PbImg_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                if (vScrollBar1.Value - rowHeight > 0)
                {
                    vScrollBar1.Value -= rowHeight;
                }
                else
                {
                    vScrollBar1.Value = vScrollBar1.Minimum;
                }

            }
            else
            {
                if (vScrollBar1.Value + rowHeight < vScrollBar1.Maximum)
                {
                    vScrollBar1.Value += rowHeight;
                }
                else
                {
                    vScrollBar1.Value = vScrollBar1.Maximum;
                }
            }
            if (MapLocationY != vScrollBar1.Value)
            {
                MapLocationY = vScrollBar1.Value;
                pbImg.Refresh();
            }

        }



        public void CalcMapSize()
        {
            float w = 0, h = 0;
            foreach (UserRow c1 in HeadColumns.Values)
            {
                float w1 = c1.CalcMaxWidth();
                if (w < w1)
                {
                    w = w1;
                }
                
            }
            rowWidth = w;
            if (rowWidth > pbImg.Width)
            {
                hScrollBar1.Enabled = true;
                hScrollBar1.Minimum = 0;
                hScrollBar1.Maximum = (int)rowWidth - pbImg.Width +10;
                hScrollBar1.LargeChange = 10;
                hScrollBar1.SmallChange = 10;
            }
            else
            {
                rowWidth = pbImg.Width;
                MapLocationX = 0;
                hScrollBar1.Enabled = false;
                //hScrollBar1.Visible = false;
            }

            foreach (UserRow u1 in Rows)
            {
                h += rowHeight;              
                if(u1.Expand)
                {
                    foreach (UserRow u2 in u1.SubRows)
                    {
                        h += rowHeight;
                       
                        if (u2.Expand)
                        {
                            foreach (UserRow u3 in u2.SubRows)
                            {
                                h += rowHeight;
                                
                            }
                        }
                    }
                }
            }
            

            int vscrollmaxNum = (int)h - pbImg.Height + 20;
            if (vscrollmaxNum != vScrollBar1.Maximum)
            {
                if (h > pbImg.Height)
                {
                    vScrollBar1.Enabled = true;
                    vScrollBar1.Minimum = 0;
                    vScrollBar1.Maximum = vscrollmaxNum;
                    vScrollBar1.LargeChange = rowHeight;
                    vScrollBar1.SmallChange = rowHeight;
                    
                }
                else
                {
                    MapLocationY = 0;
                    vScrollBar1.Enabled = false;
                }

            }
            
           
            
        }


        void Drawing(Graphics g)
        {
            float pointX = 0;
            float pointY = rowHeight;
            float scrollY = this.vScrollBar1.Value;
            //float tempHeight = scrollY + this.panel2.ClientSize.Height;
            float tempHeight = this.vScrollBar1.Value + pbImg.Height;
            
            foreach (UserRow u1 in Rows)
            {
                if (pointY <= tempHeight && pointY >= scrollY)
                {
                    u1.Draw(g, pointX, pointY, MapLocationX, MapLocationY, rowHeight, rowWidth, HeadColumns[u1.Level].Cells);
                }

                pointY += rowHeight;

                if (u1.Expand == true)
                {
                    foreach (UserRow u2 in u1.SubRows)
                    {
                        if (pointY <= tempHeight && pointY >= scrollY)
                        {
                            u2.Draw(g, pointX, pointY, MapLocationX, MapLocationY, rowHeight, rowWidth, HeadColumns[u2.Level].Cells);
                        }

                        pointY += rowHeight;
                        if (u2.Expand)
                        {
                            foreach (UserRow u3 in u2.SubRows)
                            {
                                if (pointY <= tempHeight && pointY >= scrollY)
                                {
                                    u3.Draw(g, pointX, pointY, MapLocationX, MapLocationY, rowHeight, rowWidth, HeadColumns[u3.Level].Cells);
                                }

                                pointY += rowHeight;
                            }
                        }
                    }
                }
            }

        }

        void DrawHead(Graphics g)
        {
            StringFormat strFmt = new System.Drawing.StringFormat();
            strFmt.Alignment = StringAlignment.Near; //文字水平居中
            strFmt.LineAlignment = StringAlignment.Center; //文字垂直居中

            Rectangle rect = new Rectangle(0, 0, (int)rowWidth + 10, rowHeight);
            Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(rect, Color.Gray, Color.LightGray, System.Drawing.Drawing2D.LinearGradientMode.Vertical);
            g.FillRectangle(b, rect);

            if (_selectRow != null)
            {
                float margleft = _selectRow.calcMarginLeft(_selectRow);
                float startPointX = margleft - MapLocationX;
                UserRow headrow = HeadColumns[_selectRow.Level];
                foreach (UserCell c in headrow.Cells)
                {
                    RectangleF rf = new RectangleF(startPointX, 2, c.Width, rowHeight - 1);
                    if (c.IsSelect)
                    {
                        g.FillRectangle(Brushes.Black, rf);
                        g.DrawString(c.Value, this.Font, Brushes.White, rf, strFmt);
                    }
                    else
                    {
                        g.FillRectangle(Brushes.Transparent, rf);
                        g.DrawString(c.Value, this.Font, Brushes.Black, rf, strFmt);
                    }
                    g.DrawLine(new Pen(Brushes.White, 1), startPointX, 0, startPointX, rowHeight);

                    startPointX += c.Width;
                }
                g.DrawLine(new Pen(Brushes.White, 1), startPointX, 0, startPointX, rowHeight);
            }

        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Drawing(g);
            DrawHead(g);
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                float y = e.Y;
                if (e.Y < rowHeight)
                {
                    UserCell headcell = SelectHeadIndex(e.X, e.Y);
                    if (headcell != null)
                    {
                        this.pbImg.Refresh();
                    }
                }
                else
                {
                    UserRow tempselectRow = SelectRow(e.X + MapLocationX, e.Y + MapLocationY);
                    if (tempselectRow != null)
                    {
                        if (tempselectRow != _selectRow)
                        {
                            if (_selectRow != null)
                            {
                                _selectRow.IsSelected = false;
                                if (tempselectRow.Level != _selectRow.Level)
                                {
                                    foreach (UserCell c in HeadColumns[_selectRow.Level].Cells)
                                    {
                                        c.IsSelect = false;
                                    }
                                }
                            }
                        }
                        _selectRow = tempselectRow;
                        if (tempselectRow.ExpandEvent)
                        {
                            CalcMapSize();

                        }
                        this.pbImg.Refresh();
                    }
                }

            }
        }

        UserCell SelectHeadIndex(float x, float y)
        {
            if (_selectRow != null)
            {
                UserRow headrow = HeadColumns[_selectRow.Level];
                if (headrow != null)
                {
                    float margleft = _selectRow.calcMarginLeft(_selectRow);
                    float startPointX = margleft - MapLocationX;
                    foreach (UserCell c in headrow.Cells)
                    {                       
                        if (x >= startPointX && x <= startPointX + c.Width && y > 0 && y < rowHeight)
                        {
                            c.IsSelect = !c.IsSelect;
                            return c;
                        }
                        startPointX += c.Width;
                    }
                }
            }
            return null;
        }
        UserRow SelectRow(float x, float y)
        {
            Console.WriteLine("選擇座標:x= " + x + " y= " + y);
            
            foreach (UserRow u1 in Rows)
            {
                if (u1.IsSelect(x, y, rowHeight, rowWidth))
                {
                    return u1;
                }
                else if (u1.Expand == true)
                {
                    foreach (UserRow u2 in u1.SubRows)
                    {
                        if (u2.IsSelect(x, y, rowHeight, rowWidth))
                        {
                            return u2;
                        }
                        else if (u2.Expand)
                        {
                            foreach (UserRow u3 in u2.SubRows)
                            {
                                if (u3.IsSelect(x, y, rowHeight, rowWidth))
                                {
                                    return u3;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

        private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            //System.Threading.Thread.Sleep(5);
            //MapLocationY = e.OldValue;
            //Console.WriteLine("old:" + e.OldValue);
            //Console.WriteLine("new:"+e.NewValue);
            //this.pbImg.Refresh();
            
        }

        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            //MapLocationX = e.NewValue;
            //Console.WriteLine("new:" + e.NewValue);
            //this.pbImg.Refresh();
        }

        private void UserControl1_Resize(object sender, EventArgs e)
        {
        }

        private void pbImg_Resize(object sender, EventArgs e)
        {
            CalcMapSize();
            this.pbImg.Refresh();
        }

        private void vScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            MapLocationY = vScrollBar1.Value;
            this.pbImg.Refresh();
        }

        private void hScrollBar1_ValueChanged(object sender, EventArgs e)
        {
            MapLocationX = hScrollBar1.Value;
            this.pbImg.Refresh();
        }

        private void 摺疊層一ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (UserRow u1 in Rows)
            {
                u1.Expand = false;
                
            }
            if (_selectRow != null && _selectRow.Level!= 0)
            {
                _selectRow.Expand = false;
            }
            CalcMapSize();
            this.pbImg.Refresh();
        }

        private void 摺疊層二ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (UserRow u1 in Rows)
            {
                foreach (UserRow u2 in u1.SubRows)
                {
                    u2.Expand = false;
                    //foreach (UserRow u3 in u2.SubRows)
                    //{

                    //}
                }

            }
            if (_selectRow != null && _selectRow.Level > 1)
            {
                _selectRow.Expand = false;
            }
            CalcMapSize();
            this.pbImg.Refresh();
        }

        

        private void 展開層一ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (UserRow u1 in Rows)
            {
                u1.Expand = true;
               

            }
            CalcMapSize();
            this.pbImg.Refresh();
        }

        private void 展開層二ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (UserRow u1 in Rows)
            {
                u1.Expand = true;
                foreach (UserRow u2 in u1.SubRows)
                {
                    u2.Expand = true;
                    //foreach (UserRow u3 in u2.SubRows)
                    //{

                    //}
                }

            }
            CalcMapSize();
            this.pbImg.Refresh();
        }
    }
}

4 最後在FORM介面中使用

首先需要生成資料來源

public List<UserRow> Rows = new List<UserRow>();

        SortedList<int, UserRow> HeadColumns = new SortedList<int, UserRow>();

void BuildData()
        {
            for (int i = 0; i < 100; i++)
            {
                UserRow u1 = Packdata(0, i.ToString());
                u1.Expand = true;
                for (int j = 0; j < 5; j++)
                {
                    UserRow u2 = Packdata(1, i.ToString() + "-" + j.ToString());
                    u2.Parent = u1;
                    u2.Expand = true;
                    u1.SubRows.Add(u2);

                    for (int k = 0; k < 200; k++)
                    {
                        UserRow u3 = Packdata(2, i.ToString() + "-" + j.ToString() + "-" + k.ToString());
                        u3.Parent = u2;
                        u2.SubRows.Add(u3);
                    }
                }

                Rows.Add(u1);
            }

            HeadColumns.Add(0, PackHead(0));
            HeadColumns.Add(1, PackHead(1));
            HeadColumns.Add(2, PackHead(2));
        }

UserRow Packdata(int level, string index)
        {
            UserRow u = new UserRow(level);
            for (int i = 0; i < 10; i++)
            {
                UserCell cell = new UserCell();
                cell.Value = index + "-" + i.ToString();
                u.Cells.Add(cell);
            }

            return u;
        }

        UserRow PackHead(int level)
        {
            UserRow u = new UserRow(level);
            for (int i = 0; i < 10; i++)
            {
                UserCell cell = new UserCell();
                cell.Value = "" + level + "-" + i;
                u.Cells.Add(cell);
            }

            return u;
        }

最後把控制元件新增到form窗體中

private void Form2_Load(object sender, EventArgs e)
        {
            BuildData();
            UserControl1 uct = new UserControl1(Rows);
            uct.HeadColumns = HeadColumns;
            this.Controls.Add(uct);
            uct.Dock = DockStyle.Fill;
        }

DEMO程式碼雖然比較粗糙,但是不影響使用。

轉載麻煩指明出處。。。