C#自定義組件實現(xiàn)表格的多層表頭功能
在 WinForms 中,想要實現(xiàn)多層表頭功能時,DataGridView 本身并不支持該功能,而且又不希望使用第三方控件,因此選擇通過自定義組件來實現(xiàn)這一需求。
首先,展示一下程序?qū)崿F(xiàn)的效果:
接下來,創(chuàng)建一個繼承自 DataGridView
的自定義組件。代碼如下:
using System; using System.ComponentModel; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Windows.Forms; using System.Collections; using System.Drawing; namespace CellPaintingDataGridView { public partial class TreeHeadDataGridView : DataGridView { private TreeView treeView1=new TreeView(); public TreeHeadDataGridView() { InitializeComponent(); } public TreeHeadDataGridView(IContainer container) { container.Add(this); InitializeComponent(); } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public TreeNodeCollection HeadSource { get { return this.treeView1.Nodes; } } private int _cellHeight = 17; private int _columnDeep = 1; [Description("設(shè)置或獲得合并表頭樹的深度")] public int ColumnDeep { get { if (this.Columns.Count == 0) _columnDeep = 1; this.ColumnHeadersHeight = _cellHeight * _columnDeep; return _columnDeep; } set { if (value < 1) _columnDeep = 1; else _columnDeep = value; this.ColumnHeadersHeight = _cellHeight * _columnDeep; } } ///<summary> ///繪制合并表頭 ///</summary> ///<param name="node">合并表頭節(jié)點</param> ///<param name="e">繪圖參數(shù)集</param> ///<param name="level">結(jié)點深度</param> ///<remarks></remarks> public void PaintUnitHeader(TreeNode node, DataGridViewCellPaintingEventArgs e, int level) { //根節(jié)點時退出遞歸調(diào)用 if (level == 0) return; RectangleF uhRectangle; int uhWidth; SolidBrush gridBrush = new SolidBrush(this.GridColor); Pen gridLinePen = new Pen(gridBrush); StringFormat textFormat = new StringFormat(); textFormat.Alignment = StringAlignment.Center; uhWidth = GetUnitHeaderWidth(node); //與原貼算法有所區(qū)別在這。 if (node.Nodes.Count == 0) { uhRectangle = new Rectangle(e.CellBounds.Left, e.CellBounds.Top + node.Level * _cellHeight, uhWidth - 1, _cellHeight * (_columnDeep - node.Level) - 1); } else { uhRectangle = new Rectangle( e.CellBounds.Left, e.CellBounds.Top + node.Level * _cellHeight, uhWidth - 1, _cellHeight - 1); } Color backColor = e.CellStyle.BackColor; if (node.BackColor != Color.Empty) { backColor = node.BackColor; } SolidBrush backColorBrush = new SolidBrush(backColor); //畫矩形 e.Graphics.FillRectangle(backColorBrush, uhRectangle); //劃底線 e.Graphics.DrawLine(gridLinePen , uhRectangle.Left , uhRectangle.Bottom , uhRectangle.Right , uhRectangle.Bottom); //劃右端線 e.Graphics.DrawLine(gridLinePen , uhRectangle.Right , uhRectangle.Top , uhRectangle.Right , uhRectangle.Bottom); 寫字段文本 Color foreColor = Color.Black; if (node.ForeColor != Color.Empty) { foreColor = node.ForeColor; } e.Graphics.DrawString(node.Text, this.Font , new SolidBrush(foreColor) , uhRectangle.Left + uhRectangle.Width / 2 - e.Graphics.MeasureString(node.Text, this.Font).Width / 2 - 1 , uhRectangle.Top + uhRectangle.Height / 2 - e.Graphics.MeasureString(node.Text, this.Font).Height / 2); 遞歸調(diào)用() if (node.PrevNode == null) if (node.Parent != null) PaintUnitHeader(node.Parent, e, level - 1); } /// <summary> /// 獲得合并標題字段的寬度 /// </summary> /// <param name="node">字段節(jié)點</param> /// <returns>字段寬度</returns> /// <remarks></remarks> private int GetUnitHeaderWidth(TreeNode node) { //獲得非最底層字段的寬度 int uhWidth = 0; //獲得最底層字段的寬度 if (node.Nodes == null) return this.Columns[GetColumnListNodeIndex(node)].Width; if (node.Nodes.Count == 0) return this.Columns[GetColumnListNodeIndex(node)].Width; for (int i = 0; i <= node.Nodes.Count - 1; i++) { uhWidth = uhWidth + GetUnitHeaderWidth(node.Nodes[i]); } return uhWidth; } /// <summary> /// 獲得底層字段索引 /// </summary> /// <param name="node">底層字段節(jié)點</param> /// <returns>索引</returns> /// <remarks></remarks> private int GetColumnListNodeIndex(TreeNode node) { for (int i = 0; i <= _columnList.Count - 1; i++) { if (((TreeNode)_columnList[i]).Equals(node)) return i; } return -1; } private List<TreeNode> _columnList = new List<TreeNode>(); [Description("最底層結(jié)點集合")] public List<TreeNode> NadirColumnList { get { if (this.treeView1 == null) return null; if (this.treeView1.Nodes == null) return null; if (this.treeView1.Nodes.Count == 0) return null; _columnList.Clear(); foreach (TreeNode node in this.treeView1.Nodes) { //GetNadirColumnNodes(_columnList, node, false); GetNadirColumnNodes(_columnList, node); } return _columnList; } } private void GetNadirColumnNodes(List<TreeNode> alList, TreeNode node) { if (node.FirstNode == null) { alList.Add(node); } foreach (TreeNode n in node.Nodes) { GetNadirColumnNodes(alList, n); } } /// <summary> /// 獲得底層字段集合 /// </summary> /// <param name="alList">底層字段集合</param> /// <param name="node">字段節(jié)點</param> /// <param name="checked">向上搜索與否</param> /// <remarks></remarks> private void GetNadirColumnNodes(List<TreeNode> alList, TreeNode node, Boolean isChecked) { if (isChecked == false) { if (node.FirstNode == null) { alList.Add(node); if (node.NextNode != null) { GetNadirColumnNodes(alList, node.NextNode, false); return; } if (node.Parent != null) { GetNadirColumnNodes(alList, node.Parent, true); return; } } else { if (node.FirstNode != null) { GetNadirColumnNodes(alList, node.FirstNode, false); return; } } } else { if (node.FirstNode == null) { return; } else { if (node.NextNode != null) { GetNadirColumnNodes(alList, node.NextNode, false); return; } if (node.Parent != null) { GetNadirColumnNodes(alList, node.Parent, true); return; } } } } /// <summary> /// 單元格繪制(重寫) /// </summary> /// <param name="e"></param> /// <remarks></remarks> protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e) { //行標題不重寫 if (e.ColumnIndex < 0) { base.OnCellPainting(e); return; } if (_columnDeep == 1) { base.OnCellPainting(e); return; } //繪制表頭 if (e.RowIndex == -1) { PaintUnitHeader((TreeNode)NadirColumnList[e.ColumnIndex], e, _columnDeep); e.Handled = true; } } } }
完成組件開發(fā)后,可以將該控件從工具箱拖入界面,表頭的節(jié)點設(shè)置通過 Designer.cs 中的 "Windows 窗體設(shè)計器生成的代碼" 實現(xiàn)。我們使用 System.Windows.Forms.TreeNode
來實現(xiàn)父子節(jié)點的綁定。示例代碼如下:
namespace CellPaintingDataGridView { partial class Form1 { /// <summary> /// 必需的設(shè)計器變量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的資源。 /// </summary> /// <param name="disposing">如果應(yīng)釋放托管資源,為 true;否則為 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗體設(shè)計器生成的代碼 /// <summary> /// 設(shè)計器支持所需的方法 - 不要 /// 使用代碼編輯器修改此方法的內(nèi)容。 /// </summary> private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("節(jié)點0"); System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("節(jié)點1-0-0"); System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("節(jié)點1-0-1"); System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("節(jié)點1-0", new System.Windows.Forms.TreeNode[] { treeNode2, treeNode3}); System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("節(jié)點1-1"); System.Windows.Forms.TreeNode treeNode6 = new System.Windows.Forms.TreeNode("節(jié)點1", new System.Windows.Forms.TreeNode[] { treeNode4, treeNode5}); System.Windows.Forms.TreeNode treeNode7 = new System.Windows.Forms.TreeNode("節(jié)點2-0"); System.Windows.Forms.TreeNode treeNode8 = new System.Windows.Forms.TreeNode("節(jié)點2-1"); System.Windows.Forms.TreeNode treeNode9 = new System.Windows.Forms.TreeNode("節(jié)點2-0"); System.Windows.Forms.TreeNode treeNode10 = new System.Windows.Forms.TreeNode("節(jié)點2", new System.Windows.Forms.TreeNode[] { treeNode7, treeNode8, treeNode9}); System.Windows.Forms.TreeNode treeNode11 = new System.Windows.Forms.TreeNode("節(jié)點3-0"); System.Windows.Forms.TreeNode treeNode12 = new System.Windows.Forms.TreeNode("節(jié)點3-1"); System.Windows.Forms.TreeNode treeNode13 = new System.Windows.Forms.TreeNode("節(jié)點3", new System.Windows.Forms.TreeNode[] { treeNode11, treeNode12}); this.treeHeadDataGridView1 = new CellPaintingDataGridView.TreeHeadDataGridView(this.components); this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column3 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column4 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column5 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column6 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column7 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column8 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column9 = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.treeHeadDataGridView1)).BeginInit(); this.SuspendLayout(); // // treeHeadDataGridView1 // this.treeHeadDataGridView1.ColumnDeep = 3; this.treeHeadDataGridView1.ColumnHeadersHeight = 51; this.treeHeadDataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; this.treeHeadDataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.Column1, this.Column2, this.Column3, this.Column4, this.Column5, this.Column6, this.Column7, this.Column8, this.Column9}); treeNode1.Name = "節(jié)點"; treeNode1.Text = "節(jié)點0"; treeNode2.Name = "節(jié)點1-0-0"; treeNode2.Text = "節(jié)點1-0-0"; treeNode3.Name = "節(jié)點1-0-1"; treeNode3.Text = "節(jié)點1-0-1"; treeNode4.Name = "節(jié)點1-0"; treeNode4.Text = "節(jié)點1-0"; treeNode5.Name = "節(jié)點1-1"; treeNode5.Text = "節(jié)點1-1"; treeNode6.Name = "節(jié)點1"; treeNode6.Text = "節(jié)點1"; treeNode7.Name = "節(jié)點2-0"; treeNode7.Text = "節(jié)點2-0"; treeNode8.Name = "節(jié)點2-1"; treeNode8.Text = "節(jié)點2-1"; treeNode9.Name = "節(jié)點2-0"; treeNode9.Text = "節(jié)點2-0"; treeNode10.Name = "節(jié)點2"; treeNode10.Text = "節(jié)點2"; treeNode11.Name = "節(jié)點3-0"; treeNode11.Text = "節(jié)點3-0"; treeNode12.Name = "節(jié)點3-1"; treeNode12.Text = "節(jié)點3-1"; treeNode13.Name = "節(jié)點3"; treeNode13.Text = "節(jié)點3"; this.treeHeadDataGridView1.HeadSource.AddRange(new System.Windows.Forms.TreeNode[] { treeNode1, treeNode6, treeNode10, treeNode13}); this.treeHeadDataGridView1.Location = new System.Drawing.Point(12, 12); this.treeHeadDataGridView1.Name = "treeHeadDataGridView1"; this.treeHeadDataGridView1.RowTemplate.Height = 23; this.treeHeadDataGridView1.Size = new System.Drawing.Size(1034, 456); this.treeHeadDataGridView1.TabIndex = 0; // // Column1 // this.Column1.HeaderText = "Column1"; this.Column1.Name = "Column1"; this.Column1.Width = 110; // // Column2 // this.Column2.FillWeight = 80F; this.Column2.HeaderText = "Column2"; this.Column2.Name = "Column2"; // // Column3 // this.Column3.FillWeight = 60F; this.Column3.HeaderText = "Column3"; this.Column3.Name = "Column3"; this.Column3.Width = 160; // // Column4 // this.Column4.HeaderText = "Column4"; this.Column4.Name = "Column4"; // // Column5 // this.Column5.HeaderText = "Column5"; this.Column5.Name = "Column5"; // // Column6 // this.Column6.HeaderText = "Column6"; this.Column6.Name = "Column6"; // // Column7 // this.Column7.HeaderText = "Column7"; this.Column7.Name = "Column7"; // // Column8 // this.Column8.HeaderText = "Column8"; this.Column8.Name = "Column8"; // // Column9 // this.Column9.HeaderText = "Column9"; this.Column9.Name = "Column9"; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1077, 533); this.Controls.Add(this.treeHeadDataGridView1); this.Name = "Form1"; this.Text = "Form1"; ((System.ComponentModel.ISupportInitialize)(this.treeHeadDataGridView1)).EndInit(); this.ResumeLayout(false); } #endregion private TreeHeadDataGridView treeHeadDataGridView1; private System.Windows.Forms.DataGridViewTextBoxColumn Column1; private System.Windows.Forms.DataGridViewTextBoxColumn Column2; private System.Windows.Forms.DataGridViewTextBoxColumn Column3; private System.Windows.Forms.DataGridViewTextBoxColumn Column4; private System.Windows.Forms.DataGridViewTextBoxColumn Column5; private System.Windows.Forms.DataGridViewTextBoxColumn Column6; private System.Windows.Forms.DataGridViewTextBoxColumn Column7; private System.Windows.Forms.DataGridViewTextBoxColumn Column8; private System.Windows.Forms.DataGridViewTextBoxColumn Column9; } }
通過這種方式,我們成功實現(xiàn)了多層表頭的功能,完全依賴自定義組件,不需要第三方控件。
到此這篇關(guān)于C#自定義組件實現(xiàn)表格的多層表頭功能的文章就介紹到這了,更多相關(guān)C#多層表頭內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# Distinct和重寫IEqualityComparer時要知道的二三事
這篇文章主要給大家介紹了關(guān)于C# Distinct和重寫IEqualityComparer時要知道的二三事,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06windows下C#定時管理器框架Task.MainForm詳解
這篇文章主要為大家詳細介紹了windows下C#定時管理器框架Task.MainForm的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06C#實現(xiàn)觀察者模式(Observer?Pattern)的兩種方式
這篇文章介紹了C#實現(xiàn)觀察者模式(Observer?Pattern)的兩種方式,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08C#語法糖(Csharp Syntactic sugar)大匯總
首先需要聲明的是“語法糖”這個詞絕非貶義詞,它可以給我?guī)矸奖悖且环N便捷的寫法,編譯器會幫我們做轉(zhuǎn)換;而且可以提高開發(fā)編碼的效率,在性能上也不會帶來損失。這讓java開發(fā)人員羨慕不已,呵呵。2010-06-06Unity3D運行報DllNotFoundException錯誤的解決方案
這篇文章主要介紹了Unity3D運行報DllNotFoundException錯誤的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04