Click here to Skip to main content
15,886,085 members
Articles / Desktop Programming / Windows Forms

DataGridVewTextBoxCell with Span Behaviour

Rate me:
Please Sign up or sign in to vote.
4.92/5 (41 votes)
18 Jun 2013CPOL1 min read 277.4K   17.4K   102   114
DataGridViewTextBoxCell derived cell that can be merged with cells of the same type
Image 1

Introduction

The standard System.Windows.Forms.DataGridView cells do not support merging the normal way. At some forums, developers advise the use of the CellPainting event of DataGridView. But this solution is not good if you need to realize complicated mergings. DataGridViewTextBoxCellEx supports spanning without any additional code.

Using the Code

To use DataGridViewTextBoxCellEx in a project, include the DataGridViewTextBoxCellEx.cs file, and then you can add DataGridViewTextBoxColumnEx in the columns editor of the DataGridView control.

Merging of cells is performed by setting the ColumnSpan and RowSpan properties of the left top DataGridViewTextBoxCellEx cell of the target region. For successful merging, all cells of the region must be of the DataGridViewTextBoxCellEx type.

C#
var cell = (DataGridViewTextBoxCellEx)dataGridView1[0, 0];
cell.ColumnSpan = 3;
cell.RowSpan = 2;

As a result, the dataGridView1[0, 0] cell will occupy the region from (0, 0) to (2, 1) (see screenshot at the top). The merged cell will look as the top left cell of the region. And if you wish to address a merged cell, you need to address the top left cell of the merged region. The merged region will look and behave as a normal System.Windows.Forms.DataGridViewTextBoxCell. You can edit it the standard way (pressing F2, clicking or typing text).

DataGridViewTextBoxCellEx also has a property OwnerCell. For unmerged cells and for the left top cells of the merged regions, it is null. For other cells of the merged region, the property points to the left top cell.

History

  • 11th March, 2009: Initial post
  • 9th March, 2010: Article updated
  • 21st December, 2010: Demo and source files updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer EKRA
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionLooks like what I want to do Pin
Lee Belcher22-Jan-12 14:17
Lee Belcher22-Jan-12 14:17 
AnswerRe: Looks like what I want to do Pin
Sergey Semyonov22-Jan-12 20:10
Sergey Semyonov22-Jan-12 20:10 
GeneralRe: Looks like what I want to do Pin
nimolZero23-May-12 23:27
nimolZero23-May-12 23:27 
Questiondoublebuffering Pin
xboxproject19-Apr-11 1:16
xboxproject19-Apr-11 1:16 
AnswerRe: doublebuffering Pin
Sergey Semyonov25-Apr-11 0:32
Sergey Semyonov25-Apr-11 0:32 
GeneralRe: doublebuffering Pin
xboxproject26-Apr-11 1:08
xboxproject26-Apr-11 1:08 
AnswerRe: doublebuffering Pin
Sergey Semyonov27-Apr-11 4:30
Sergey Semyonov27-Apr-11 4:30 
GeneralRe: doublebuffering Pin
tipsybroom5-Jun-13 4:21
tipsybroom5-Jun-13 4:21 
Following code worked for me. But I don't know why. Smile | Smile | :) Replace your Paint method with this:

C#
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            if (_ownerCell != null && _ownerCell.DataGridView == null)
            {
                _ownerCell = null; //owner cell was removed.
            }

            if (DataGridView == null || (_ownerCell == null && _columnSpan == 1 && _rowSpan == 1))
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                return;
            }

            var ownerCell = this;
            var columnIndex = ColumnIndex;
            var columnSpan = _columnSpan;
            var rowSpan = _rowSpan;
            if (_ownerCell != null)
            {
                ownerCell = _ownerCell;
                columnIndex = _ownerCell.ColumnIndex;
                rowIndex = _ownerCell.RowIndex;
                columnSpan = _ownerCell.ColumnSpan;
                rowSpan = _ownerCell.RowSpan;
                value = _ownerCell.GetValue(rowIndex);
                errorText = _ownerCell.GetErrorText(rowIndex);
                cellState = _ownerCell.State;
                cellStyle = _ownerCell.GetInheritedStyle(null, rowIndex, true);
                formattedValue = _ownerCell.GetFormattedValue(value, rowIndex, ref cellStyle, null, null, DataGridViewDataErrorContexts.Display);
            }

            if (CellsRegionContainsSelectedCell(columnIndex, rowIndex, columnSpan, rowSpan))
            {
                cellState |= DataGridViewElementStates.Selected;
            }

            // Store the old Clip Bound
            RectangleF oldBounds = graphics.ClipBounds;
            var cellBounds2 = DataGridViewCellExHelper.GetSpannedCellBoundsFromChildCellBounds(this, cellBounds, DataGridView.SingleVerticalBorderAdded(), DataGridView.SingleHorizontalBorderAdded());
            clipBounds = DataGridViewCellExHelper.GetSpannedCellClipBounds(ownerCell, cellBounds2, DataGridView.SingleVerticalBorderAdded(), DataGridView.SingleHorizontalBorderAdded());

            advancedBorderStyle = DataGridViewCellExHelper.AdjustCellBorderStyle(ownerCell);

            using (var g = this.DataGridView.CreateGraphics())
            {
                // Set the new Clip Bounds to the bounds which are calulcated for the row to span.
                g.SetClip(clipBounds);

                //Paint the content.
                ownerCell.NativePaint(g, clipBounds, cellBounds2, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.Border);

                //Paint the borders.
                if ((paintParts & DataGridViewPaintParts.Border) != DataGridViewPaintParts.None)
                {
                    var leftTopCell = ownerCell;
                    var advancedBorderStyle2 = new DataGridViewAdvancedBorderStyle
                    {
                        Left = advancedBorderStyle.Left,
                        Top = advancedBorderStyle.Top,
                        Right = DataGridViewAdvancedCellBorderStyle.None,
                        Bottom = DataGridViewAdvancedCellBorderStyle.None
                    };
                    leftTopCell.PaintBorder(g, clipBounds, cellBounds2, cellStyle, advancedBorderStyle2);

                    var rightBottomCell = DataGridView[columnIndex + columnSpan - 1, rowIndex + rowSpan - 1] as DataGridViewSpannedTextBoxCell ?? this;
                    var advancedBorderStyle3 = new DataGridViewAdvancedBorderStyle
                    {
                        Left = DataGridViewAdvancedCellBorderStyle.None,
                        Top = DataGridViewAdvancedCellBorderStyle.None,
                        Right = advancedBorderStyle.Right,
                        Bottom = advancedBorderStyle.Bottom
                    };
                    rightBottomCell.PaintBorder(g, clipBounds, cellBounds2, cellStyle, advancedBorderStyle3);

                }
            }

            // Set the new Clip Bounds to the bounds which are calulcated for the row to span.
            graphics.SetClip(clipBounds);

            //Paint the content.
            ownerCell.NativePaint(graphics, clipBounds, cellBounds2, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts & ~DataGridViewPaintParts.Border);

            //Paint the borders.
            if ((paintParts & DataGridViewPaintParts.Border) != DataGridViewPaintParts.None)
            {
                var leftTopCell = ownerCell;
                var advancedBorderStyle2 = new DataGridViewAdvancedBorderStyle
                {
                    Left = advancedBorderStyle.Left,
                    Top = advancedBorderStyle.Top,
                    Right = DataGridViewAdvancedCellBorderStyle.None,
                    Bottom = DataGridViewAdvancedCellBorderStyle.None
                };
                leftTopCell.PaintBorder(graphics, clipBounds, cellBounds2, cellStyle, advancedBorderStyle2);

                var rightBottomCell = DataGridView[columnIndex + columnSpan - 1, rowIndex + rowSpan - 1] as DataGridViewSpannedTextBoxCell ?? this;
                var advancedBorderStyle3 = new DataGridViewAdvancedBorderStyle
                {
                    Left = DataGridViewAdvancedCellBorderStyle.None,
                    Top = DataGridViewAdvancedCellBorderStyle.None,
                    Right = advancedBorderStyle.Right,
                    Bottom = advancedBorderStyle.Bottom
                };
                rightBottomCell.PaintBorder(graphics, clipBounds, cellBounds2, cellStyle, advancedBorderStyle3);

            }

            // Restore old Bounds! Otherwise only the spanned row will be painted
            graphics.SetClip(oldBounds);
        }

Generallast question for this fabulous control :-) Pin
gertdebusser15-Dec-10 23:53
gertdebusser15-Dec-10 23:53 
GeneralRe: last question for this fabulous control :-) Pin
Sergey Semyonov16-Dec-10 3:18
Sergey Semyonov16-Dec-10 3:18 
GeneralRe: last question for this fabulous control :-) Pin
Sergey Semyonov21-Dec-10 2:08
Sergey Semyonov21-Dec-10 2:08 
Generaldouble question Pin
gertdebusser8-Nov-10 23:31
gertdebusser8-Nov-10 23:31 
GeneralRe: double question Pin
Sergey Semyonov9-Nov-10 1:18
Sergey Semyonov9-Nov-10 1:18 
GeneralRe: double question Pin
gertdebusser9-Nov-10 5:19
gertdebusser9-Nov-10 5:19 
GeneralRe: double question Pin
Sergey Semyonov11-Nov-10 20:26
Sergey Semyonov11-Nov-10 20:26 
GeneralBug when frozen cells Pin
CLOPEZ8-Nov-10 17:52
CLOPEZ8-Nov-10 17:52 
GeneralRe: Bug when frozen cells Pin
Sergey Semyonov8-Nov-10 20:26
Sergey Semyonov8-Nov-10 20:26 
GeneralRe: Bug when frozen cells Pin
CLOPEZ9-Nov-10 4:37
CLOPEZ9-Nov-10 4:37 
GeneralRe: Bug when frozen cells Pin
Sergey Semyonov11-Nov-10 20:27
Sergey Semyonov11-Nov-10 20:27 
GeneralBug with RTL ... Pin
A7mad_13-Jul-10 13:08
A7mad_13-Jul-10 13:08 
GeneralRe: Bug with RTL ... Pin
Sergey Semyonov13-Jul-10 23:13
Sergey Semyonov13-Jul-10 23:13 
GeneralRe: Bug with RTL ... Pin
Sergey Semyonov15-Jul-10 21:29
Sergey Semyonov15-Jul-10 21:29 
GeneralFirst Row/Column Problem Pin
Gennadiy, Erlangen9-Mar-10 3:27
Gennadiy, Erlangen9-Mar-10 3:27 
GeneralRe: First Row/Column Problem Pin
Sergey Semyonov10-Mar-10 6:03
Sergey Semyonov10-Mar-10 6:03 
GeneralRe: First Row/Column Problem Pin
Gennadiy, Erlangen11-Mar-10 1:34
Gennadiy, Erlangen11-Mar-10 1:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.