Monday, February 6, 2012

Merged Column Headers and Vertical Column Text in DataGridView


Finally, I’ve been able to find a solution to have both vertical column headers text and merged column headers in the DataGridView in C#. The idea is to handle the Paint event and draw the column headers. In case of vertical text, just changing the string format would suffice, and the following figure shows the result obtained incorporating both Vertical text and merged headers

Vertical Header Text
The following code snippet is used to obain the vertical column header text. The code is written in the ‘Cell Painting’ Event of the DataGridView. The code check whether the column header is painted, if yes then the text format is changed to cater for vertical display.
     StringFormat l_objformat = new StringFormat();

            ///////////////////////////////////////////////////////////////
            if (e.RowIndex == -1 && e.ColumnIndex > -1)
            {
                Rectangle r2 = e.CellBounds;
                r2.Y += e.CellBounds.Height / 2;
                r2.Height = e.CellBounds.Height / 2;
                e.PaintBackground(r2, true);
                e.PaintContent(r2);

               //////////////////////////////////////////////////////////////////
                e.PaintBackground(e.ClipBounds, true);
  Rectangle rect = this.dataGridView1.GetColumnDisplayRectangle (e.ColumnIndex, true);
                Size titleSize = TextRenderer.MeasureText(e.Value.ToString(), e.CellStyle.Font);
               
  if (this.dataGridView1.ColumnHeadersHeight < titleSize.Width)
                    this.dataGridView1.ColumnHeadersHeight = titleSize.Width;
              
                rect.X += e.CellBounds.Width/2;
                rect.Y +=dataGridView1.ColumnHeadersHeight/2;
                l_objformat.FormatFlags = StringFormatFlags.DirectionVertical;
                e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, Brushes.Red, rect, l_objformat);
                e.Handled = true;//This is required, else the original painting of the data grid view overwrites the changes.
            }
The text is adjusted to make it center and occur after the merged headers.
Merged Columns
The merged columns are obtained by drawing the rectangle and writing strings in the rectangle. The following code snippet written in the Paint Event to achieve merged columns.
First increase the column height to cater for the merged header, this is written in the form load event.
     dataGridView1.ColumnHeadersHeight = dataGridView1.ColumnHeadersHeight * 2;
           
Now, the following code in the DataGridView paint event is used to merge columns. The code is for generating the grid view displayed in the above figure.
string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
            for (int j = 0; j < 24; )
            {

                ////////////////////////////////////////////
                Rectangle r1 = dataGridView1.GetCellDisplayRectangle(j, -1, true);
                int w2 = dataGridView1.GetCellDisplayRectangle(j + 1, -1, true).Width;
                r1.X += 1;
                r1.Y += 1;
                r1.Width = r1.Width + w2 - 2;
                r1.Height = r1.Height / 2 - 2;
                e.Graphics.FillRectangle(new SolidBrush(dataGridView1.ColumnHeadersDefaultCellStyle.BackColor), r1);
             
                StringFormat format = new StringFormat();

                format.Alignment = StringAlignment.Center;
                format.LineAlignment = StringAlignment.Center;
                e.Graphics.DrawString(months[j / 2], dataGridView1.ColumnHeadersDefaultCellStyle.Font,
                    new SolidBrush(dataGridView1.ColumnHeadersDefaultCellStyle.ForeColor), r1, format);
                j += 2;


            }

Cater for Scrolling and Column Resizing
When the columns are resized or the scrolled across, repainting is required to redraw the columns. The Scroll and Column Resize events are handled and the columns are invalidated to force repainting.
Rectangle rtHeader = dataGridView1.DisplayRectangle;
            rtHeader.Height = dataGridView1.ColumnHeadersHeight / 2;
            dataGridView1.Invalidate(rtHeader);

Disclamer:
The Work is otherwise provided "as is", "where is", "as available", without warranty or guarantee of any kind. This means no express, implied or statutory warranty, including without limitation, warranties or conditions of merchantability or fitness for a particular purpose.


No comments: