欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

DataGridView多維表頭的實(shí)現(xiàn)方法

 更新時(shí)間:2013年04月03日 09:18:25   作者:  
不過(guò)我自己還是擴(kuò)展了DataGridView,使之能制作出多維表頭。

背景

對(duì)于.NET 原本提供的DataGridView控件,制作成如下形式的表格是毫無(wú)壓力的。

但是如果把表格改了一下,變成如下形式

傳統(tǒng)的DataGridView就做不到了,如果擴(kuò)展一下還是行的,有不少網(wǎng)友也擴(kuò)展了DataGridView控件,不過(guò)有些也只能制作出二維的表頭?;蛘呤褂玫谌降目丶?,之前也用過(guò)DevExpress的BoundGridView。不過(guò)在沒(méi)有可使用的第三方控件的情況下,做到下面的效果,就有點(diǎn)麻煩了。

那得自己擴(kuò)展了,不過(guò)最后還是用了一個(gè)控件庫(kù)的報(bào)表控件,Telerik的Reporting。不過(guò)我自己還是擴(kuò)展了DataGridView,使之能制作出上面的報(bào)表。

準(zhǔn)備

學(xué)習(xí)了一些網(wǎng)友的代碼,原來(lái)制作這個(gè)多維表頭都是利用GDI+對(duì)DataGirdView的表頭進(jìn)行重繪。

用到的方法包括

Graphics.FillRectangle //填充一個(gè)矩形

Graphics.DrawLine //畫(huà)一條線

Graphics.DrawString  //寫(xiě)字符串

此外為了方便組織表頭,本人還定義了一個(gè)表頭的數(shù)據(jù)結(jié)構(gòu) HeaderItem 和 HeaderCollection 分別作為每個(gè)表頭單元格的數(shù)據(jù)實(shí)體和整個(gè)表頭的集合。

HeaderItem的定義如下

復(fù)制代碼 代碼如下:

public class HeaderItem
     {
         private int _startX;//起始橫坐標(biāo)
         private int _startY;//起始縱坐標(biāo)
         private int _endX; //終止橫坐標(biāo)
         private int _endY; //終止縱坐標(biāo)
         private bool _baseHeader; //是否基礎(chǔ)表頭

         public HeaderItem(int startX, int endX, int startY, int endY, string content)
         {
             this._endX = endX;
             this._endY = endY;
             this._startX = startX;
             this._startY = startY;
             this.Content = content;
         }

         public HeaderItem(int x, int y, string content):this(x,x,y,y,content)
         {

         }

         public HeaderItem()
         {

         }

         public static HeaderItem CreateBaseHeader(int x,int y,string content)
         {
             HeaderItem header = new HeaderItem();
             header._endX= header._startX = x;
             header._endY= header._startY = y;
             header._baseHeader = true;
             header.Content = content;
             return header;
         }

         public int StartX
         {
             get { return _startX; }
             set
             {
                 if (value > _endX)
                 {
                     _startX = _endX;
                     return;
                 }
                 if (value < 0) _startX = 0;
                 else _startX = value;
             }
         }

         public int StartY
         {
             get { return _startY; }
             set
             {
                 if (_baseHeader)
                 {
                     _startY = 0;
                     return;
                 }
                 if (value > _endY)
                 {
                     _startY = _endY;
                     return;
                 }
                 if (value < 0) _startY = 0;
                 else _startY = value;
             }
         }

         public int EndX
         {
             get { return _endX; }
             set
             {
                 if (_baseHeader)
                 {
                     _endX = _startX;
                     return;
                 }
                 if (value < _startX)
                 {
                     _endX = _startX;
                     return;
                 }
                 _endX = value;
             }
         }

         public int EndY
         {
             get { return _endY; }
             set
             {
                 if (value < _startY)
                 {
                     _endY = _startY;
                     return;
                 }
                 _endY = value;
             }
         }

         public bool IsBaseHeader
         {get{ return _baseHeader;} }

         public string Content { get; set; }
     }

設(shè)計(jì)思想是利用數(shù)學(xué)的直角坐標(biāo)系,給每個(gè)表頭單元格定位并劃定其大小。與計(jì)算機(jī)顯示的坐標(biāo)定位不同,這里的原點(diǎn)是跟數(shù)學(xué)的一樣放在左下角,X軸正方向是水平向右,Y軸正方向是垂直向上。如下圖所示

之所以要對(duì)GridView中原始的列頭進(jìn)行特別處理,是因?yàn)檫@里的起止坐標(biāo)和終止坐標(biāo)都可以設(shè)置,而原始列頭的起始縱坐標(biāo)(StartY)只能是0,終止橫坐標(biāo)(EndX)必須與起始橫坐標(biāo)(StartY)相等。

另外所有列頭單元格的集合HeaderCollection的定義如下

復(fù)制代碼 代碼如下:

public class HeaderCollection
     {
         private List<HeaderItem> _headerList;
         private bool _iniLock;

         public DataGridViewColumnCollection BindCollection{get;set;}

         public HeaderCollection(DataGridViewColumnCollection cols)
         {
             _headerList = new List<HeaderItem>();
             BindCollection=cols;
             _iniLock = false;
         }

         public int GetHeaderLevels()
         {
             int max = 0;
             foreach (HeaderItem item in _headerList)
                 if (item.EndY > max)
                     max = item.EndY;

             return max;
         }

         public List<HeaderItem> GetBaseHeaders()
         {
             List<HeaderItem> list = new List<HeaderItem>();
             foreach (HeaderItem item in _headerList)
                 if (item.IsBaseHeader) list.Add(item);
             return list;
         }

         public HeaderItem GetHeaderByLocation(int x, int y)
         {
             if (!_iniLock) InitHeader();
             HeaderItem result=null;
             List<HeaderItem> temp = new List<HeaderItem>();
             foreach (HeaderItem item in _headerList)
                 if (item.StartX <= x && item.EndX >= x)
                     temp.Add(item);
             foreach (HeaderItem item in temp)
                 if (item.StartY <= y && item.EndY >= y)
                     result = item;

             return result;
         }

         public IEnumerator GetHeaderEnumer()
         {
             return _headerList.GetEnumerator();
         }

         public void AddHeader(HeaderItem header)
         {
             this._headerList.Add(header);
         }

         public void AddHeader(int startX, int endX, int startY, int endY, string content)
         {
             this._headerList.Add(new HeaderItem(startX,endX,startY,endY,content));
         }

         public void AddHeader(int x, int y, string content)
         {
             this._headerList.Add(new HeaderItem(x, y, content));
         }

         public void RemoveHeader(HeaderItem header)
         {
             this._headerList.Remove(header);
         }

         public void RemoveHeader(int x, int y)
         {
            HeaderItem header= GetHeaderByLocation(x, y);
            if (header != null) RemoveHeader(header);
         }

         private void InitHeader()
         {
             _iniLock = true;
             for (int i = 0; i < this.BindCollection.Count; i++)
                 if(this.GetHeaderByLocation(i,0)==null)
                 this._headerList.Add(HeaderItem.CreateBaseHeader(i,0 , this.BindCollection[i].HeaderText));
             _iniLock = false;
         }
     }

這里仿照了.NET Frameword的Collection那樣定義了Add方法和Remove方法,此外說(shuō)明一下那個(gè) GetHeaderByLocation 方法,這個(gè)方法可以通過(guò)給定的坐標(biāo)獲取那個(gè)坐標(biāo)的HeaderItem。這個(gè)坐標(biāo)是忽略了整個(gè)表頭合并單元格的情況,例如

上面這幅圖,如果輸入0,0 返回的是灰色區(qū)域,輸入2,1 或3,2 或 5,1返回的都是橙色的區(qū)域。

擴(kuò)展控件

到真正擴(kuò)展控件了,最核心的是重寫(xiě) OnCellPainting 方法,這個(gè)其實(shí)是與表格單元格重繪時(shí)觸發(fā)事件綁定的方法,通過(guò)參數(shù) DataGridViewCellPaintingEventArgs 的 ColumnIndex 和 RowIndex 屬性可以知道當(dāng)前重繪的是哪個(gè)單元格,于是就通過(guò)HeaderCollection獲取要繪制的表頭單元格的信息進(jìn)行重繪,對(duì)已經(jīng)重繪的單元格會(huì)進(jìn)行標(biāo)記,以防重復(fù)繪制。

復(fù)制代碼 代碼如下:

protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
         {
             if (e.ColumnIndex == -1 || e.RowIndex != -1)
             {
                 base.OnCellPainting(e);
                 return;
             }
             int lev=this.Headers.GetHeaderLevels();
             this.ColumnHeadersHeight = (lev + 1) * _baseColumnHeadHeight;
             for (int i = 0; i <= lev; i++)
             {
                 HeaderItem tempHeader= this.Headers.GetHeaderByLocation(e.ColumnIndex, i);
                 if (tempHeader==null|| i != tempHeader.EndY || e.ColumnIndex != tempHeader.StartX) continue;
                 DrawHeader(tempHeader, e);
             }
             e.Handled = true;
         }

上面的代碼中,最初是先判斷當(dāng)前要重繪的單元格是不是表頭部分,如果不是則調(diào)用原本的OnCellPainting方法。 e.Handled=true; 比較關(guān)鍵,有了這句代碼,重繪才能生效。

繪制單元格的過(guò)程封裝在方法DrawHeader里面

復(fù)制代碼 代碼如下:

private void DrawHeader(HeaderItem item,DataGridViewCellPaintingEventArgs e)
         {
             if (this.ColumnHeadersHeightSizeMode != DataGridViewColumnHeadersHeightSizeMode.DisableResizing)
                 this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
             int lev=this.Headers.GetHeaderLevels();
             lev=(lev-item.EndY)*_baseColumnHeadHeight;

             SolidBrush backgroundBrush = new SolidBrush(e.CellStyle.BackColor);
             SolidBrush lineBrush = new SolidBrush(this.GridColor);
             Pen linePen = new Pen(lineBrush);
             StringFormat foramt = new StringFormat();
             foramt.Alignment = StringAlignment.Center;
             foramt.LineAlignment = StringAlignment.Center;

             Rectangle headRec = new Rectangle(e.CellBounds.Left, lev, ComputeWidth(item.StartX, item.EndX)-1, ComputeHeight(item.StartY, item.EndY)-1);
             e.Graphics.FillRectangle(backgroundBrush, headRec);
             e.Graphics.DrawLine(linePen, headRec.Left, headRec.Bottom, headRec.Right, headRec.Bottom);
             e.Graphics.DrawLine(linePen, headRec.Right, headRec.Top, headRec.Right, headRec.Bottom);
             e.Graphics.DrawString(item.Content, this.ColumnHeadersDefaultCellStyle.Font, Brushes.Black,headRec, foramt);
         }

填充矩形時(shí),記得要給矩形的常和寬減去一個(gè)像素,這樣才不會(huì)與相鄰的矩形重疊區(qū)域?qū)е戮匦蔚倪吘€顯示不出來(lái)。還有這里的要設(shè)置 ColumnHeadersHeightSizeMode 屬性,如果不把它設(shè)成 DisableResizing ,那么表頭的高度是改變不了的,這樣即使設(shè)置了二維,三維,n維,最終只是一維。

這里用到的一些輔助方法如下,分別是通過(guò)坐標(biāo)計(jì)算出高度和寬度。

復(fù)制代碼 代碼如下:

private int ComputeWidth(int startX, int endX)
         {
             int width = 0;
             for (int i = startX; i <= endX; i++)
                 width+= this.Columns[i].Width;
             return width;
         }

         private int ComputeHeight(int startY, int endY)
         {
             return _baseColumnHeadHeight * (endY - startY+1);
         }

給一段使用的實(shí)例代碼,這里要預(yù)先給DataGridView每一列設(shè)好綁定的字段,否則自動(dòng)添加的列是做不出效果來(lái)的。

復(fù)制代碼 代碼如下:

HeaderItem item= this.boundGridView1.Headers.GetHeaderByLocation(0, 0);
             item.EndY = 2;
             item = this.boundGridView1.Headers.GetHeaderByLocation(9,0 );
             item.EndY = 2;
             item = this.boundGridView1.Headers.GetHeaderByLocation(10, 0);
             item.EndY = 2;
             item = this.boundGridView1.Headers.GetHeaderByLocation(11, 0);
             item.EndY = 2;

             this.boundGridView1.Headers.AddHeader(1, 2, 1, 1, "語(yǔ)文");
             this.boundGridView1.Headers.AddHeader(3, 4, 1, 1, "數(shù)學(xué)");
             this.boundGridView1.Headers.AddHeader(5, 6, 1, 1, "英語(yǔ)");
             this.boundGridView1.Headers.AddHeader(7, 8, 1, 1, "X科");
             this.boundGridView1.Headers.AddHeader(1, 8, 2, 2, "成績(jī)");

效果圖如下所示

 

總的來(lái)說(shuō)自我感覺(jué)有點(diǎn)小題大做,但想不出有什么更好的辦法,各位如果覺(jué)得以上說(shuō)的有什么不好的,歡迎拍磚;如果發(fā)現(xiàn)以上有什么說(shuō)錯(cuò)了,懇請(qǐng)批評(píng)指正;如果覺(jué)得好的,請(qǐng)支持一下。謝謝!最后附上整個(gè)控件的源碼
控件的完整代碼

復(fù)制代碼 代碼如下:


     public class BoundGridView : DataGridView
     {
         private int _baseColumnHeadHeight;

         public BoundGridView():base()
         {
             this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
             _baseColumnHeadHeight = this.ColumnHeadersHeight;
             this.Headers = new HeaderCollection(this.Columns);
         }

         public HeaderCollection Headers{ get;private set; }

         protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
         {
             if (e.ColumnIndex == -1 || e.RowIndex != -1)
             {
                 base.OnCellPainting(e);
                 return;
             }
             int lev=this.Headers.GetHeaderLevels();
             this.ColumnHeadersHeight = (lev + 1) * _baseColumnHeadHeight;
             for (int i = 0; i <= lev; i++)
             {
                 HeaderItem tempHeader= this.Headers.GetHeaderByLocation(e.ColumnIndex, i);
                 if (tempHeader==null|| i != tempHeader.EndY || e.ColumnIndex != tempHeader.StartX) continue;
                 DrawHeader(tempHeader, e);
             }
             e.Handled = true;
         }

         private int ComputeWidth(int startX, int endX)
         {
             int width = 0;
             for (int i = startX; i <= endX; i++)
                 width+= this.Columns[i].Width;
             return width;
         }

         private int ComputeHeight(int startY, int endY)
         {
             return _baseColumnHeadHeight * (endY - startY+1);
         }

         private void DrawHeader(HeaderItem item,DataGridViewCellPaintingEventArgs e)
         {
             if (this.ColumnHeadersHeightSizeMode != DataGridViewColumnHeadersHeightSizeMode.DisableResizing)
                 this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
             int lev=this.Headers.GetHeaderLevels();
             lev=(lev-item.EndY)*_baseColumnHeadHeight;

             SolidBrush backgroundBrush = new SolidBrush(e.CellStyle.BackColor);
             SolidBrush lineBrush = new SolidBrush(this.GridColor);
             Pen linePen = new Pen(lineBrush);
             StringFormat foramt = new StringFormat();
             foramt.Alignment = StringAlignment.Center;
             foramt.LineAlignment = StringAlignment.Center;

             Rectangle headRec = new Rectangle(e.CellBounds.Left, lev, ComputeWidth(item.StartX, item.EndX)-1, ComputeHeight(item.StartY, item.EndY)-1);
             e.Graphics.FillRectangle(backgroundBrush, headRec);
             e.Graphics.DrawLine(linePen, headRec.Left, headRec.Bottom, headRec.Right, headRec.Bottom);
             e.Graphics.DrawLine(linePen, headRec.Right, headRec.Top, headRec.Right, headRec.Bottom);
             e.Graphics.DrawString(item.Content, this.ColumnHeadersDefaultCellStyle.Font, Brushes.Black,headRec, foramt);
         }
     }

     public class HeaderItem
     {
         private int _startX;
         private int _startY;
         private int _endX;
         private int _endY;
         private bool _baseHeader;

         public HeaderItem(int startX, int endX, int startY, int endY, string content)
         {
             this._endX = endX;
             this._endY = endY;
             this._startX = startX;
             this._startY = startY;
             this.Content = content;
         }

         public HeaderItem(int x, int y, string content):this(x,x,y,y,content)
         {

         }

         public HeaderItem()
         {

         }

         public static HeaderItem CreateBaseHeader(int x,int y,string content)
         {
             HeaderItem header = new HeaderItem();
             header._endX= header._startX = x;
             header._endY= header._startY = y;
             header._baseHeader = true;
             header.Content = content;
             return header;
         }

         public int StartX
         {
             get { return _startX; }
             set
             {
                 if (value > _endX)
                 {
                     _startX = _endX;
                     return;
                 }
                 if (value < 0) _startX = 0;
                 else _startX = value;
             }
         }

         public int StartY
         {
             get { return _startY; }
             set
             {
                 if (_baseHeader)
                 {
                     _startY = 0;
                     return;
                 }
                 if (value > _endY)
                 {
                     _startY = _endY;
                     return;
                 }
                 if (value < 0) _startY = 0;
                 else _startY = value;
             }
         }

         public int EndX
         {
             get { return _endX; }
             set
             {
                 if (_baseHeader)
                 {
                     _endX = _startX;
                     return;
                 }
                 if (value < _startX)
                 {
                     _endX = _startX;
                     return;
                 }
                 _endX = value;
             }
         }

         public int EndY
         {
             get { return _endY; }
             set
             {
                 if (value < _startY)
                 {
                     _endY = _startY;
                     return;
                 }
                 _endY = value;
             }
         }

         public bool IsBaseHeader
         {get{ return _baseHeader;} }

         public string Content { get; set; }
     }

     public class HeaderCollection
     {
         private List<HeaderItem> _headerList;
         private bool _iniLock;

         public DataGridViewColumnCollection BindCollection{get;set;}

         public HeaderCollection(DataGridViewColumnCollection cols)
         {
             _headerList = new List<HeaderItem>();
             BindCollection=cols;
             _iniLock = false;
         }

         public int GetHeaderLevels()
         {
             int max = 0;
             foreach (HeaderItem item in _headerList)
                 if (item.EndY > max)
                     max = item.EndY;

             return max;
         }

         public List<HeaderItem> GetBaseHeaders()
         {
             List<HeaderItem> list = new List<HeaderItem>();
             foreach (HeaderItem item in _headerList)
                 if (item.IsBaseHeader) list.Add(item);
             return list;
         }

         public HeaderItem GetHeaderByLocation(int x, int y)
         {
             if (!_iniLock) InitHeader();
             HeaderItem result=null;
             List<HeaderItem> temp = new List<HeaderItem>();
             foreach (HeaderItem item in _headerList)
                 if (item.StartX <= x && item.EndX >= x)
                     temp.Add(item);
             foreach (HeaderItem item in temp)
                 if (item.StartY <= y && item.EndY >= y)
                     result = item;

             return result;
         }

         public IEnumerator GetHeaderEnumer()
         {
             return _headerList.GetEnumerator();
         }

         public void AddHeader(HeaderItem header)
         {
             this._headerList.Add(header);
         }

         public void AddHeader(int startX, int endX, int startY, int endY, string content)
         {
             this._headerList.Add(new HeaderItem(startX,endX,startY,endY,content));
         }

         public void AddHeader(int x, int y, string content)
         {
             this._headerList.Add(new HeaderItem(x, y, content));
         }

         public void RemoveHeader(HeaderItem header)
         {
             this._headerList.Remove(header);
         }

         public void RemoveHeader(int x, int y)
         {
            HeaderItem header= GetHeaderByLocation(x, y);
            if (header != null) RemoveHeader(header);
         }

         private void InitHeader()
         {
             _iniLock = true;
             for (int i = 0; i < this.BindCollection.Count; i++)
                 if(this.GetHeaderByLocation(i,0)==null)
                 this._headerList.Add(HeaderItem.CreateBaseHeader(i,0 , this.BindCollection[i].HeaderText));
             _iniLock = false;
         }
     }

相關(guān)文章

  • ASP.NET 4.0配置文件中的ClientIDMode屬性詳解

    ASP.NET 4.0配置文件中的ClientIDMode屬性詳解

    在ASP.NET 4.0中的每個(gè)控件上都多了一個(gè)叫做ClientIDMode的屬性,本文主要介紹了ASP.NET 4.0配置文件中的ClientIDMode屬性詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-11-11
  • WebForm獲取checkbox選中的值(幾個(gè)簡(jiǎn)單的示例)

    WebForm獲取checkbox選中的值(幾個(gè)簡(jiǎn)單的示例)

    WebForm中用checkbox的地方挺多的,下面寫(xiě)了幾個(gè)簡(jiǎn)單的例子,方便以后學(xué)習(xí)使用
    2014-07-07
  • 詳解.Net Core + Angular2 環(huán)境搭建

    詳解.Net Core + Angular2 環(huán)境搭建

    這篇文章主要介紹了詳解.Net Core + Angular2 環(huán)境搭建,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • 淺談ASP.NET Core 2.0 部分視圖(譯)

    淺談ASP.NET Core 2.0 部分視圖(譯)

    本篇文章主要介紹了淺談ASP.NET Core 2.0 部分視圖(譯),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • 關(guān)于中g(shù)ridview 字符串截取的方法

    關(guān)于中g(shù)ridview 字符串截取的方法

    在Gridview中,如果你的某一列字符串的長(zhǎng)度過(guò)長(zhǎng),不做處理的話.那么將顯示的奇丑無(wú)比,可以采取設(shè)置樣式,將其顯示為定長(zhǎng),可以在點(diǎn)擊查看的時(shí)候,在另一個(gè)頁(yè)面對(duì)其進(jìn)行顯示
    2013-06-06
  • ASP.NET下母版頁(yè)和內(nèi)容頁(yè)中的事件發(fā)生順序整理

    ASP.NET下母版頁(yè)和內(nèi)容頁(yè)中的事件發(fā)生順序整理

    母版頁(yè)與內(nèi)容頁(yè)合并后事件的發(fā)生順序,有需要區(qū)別的朋友能用的到
    2009-03-03
  • 詳解.NET Core中的Worker Service

    詳解.NET Core中的Worker Service

    這篇文章主要介紹了.NET Core中的Worker Service的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用.NET技術(shù),感興趣的朋友可以了解下
    2021-03-03
  • Asp.net 自帶報(bào)表的使用詳解

    Asp.net 自帶報(bào)表的使用詳解

    最近公司的功能需要使用報(bào)表,用的是微軟自帶的報(bào)表,談一談我們的做法,希望可以給想學(xué)習(xí)的人一些指導(dǎo)
    2013-10-10
  • aspnetcore 實(shí)現(xiàn)簡(jiǎn)單的偽靜態(tài)化功能

    aspnetcore 實(shí)現(xiàn)簡(jiǎn)單的偽靜態(tài)化功能

    這篇文章主要介紹了aspnetcore 實(shí)現(xiàn)簡(jiǎn)單的偽靜態(tài)化功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-07-07
  • .Net Core自定義配置源從配置中心讀取配置的方法

    .Net Core自定義配置源從配置中心讀取配置的方法

    這篇文章主要給大家介紹了關(guān)于.Net Core自定義配置源從配置中心讀取配置的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論