C# – Display user control in DatagridViewCell

c++winforms

Winforms .NET 3.5 (C#)

I have a DataGridView (DGView) and I created CustomColumn and CustomCell to be displayed in the DGView. I created a CustomUserControl which I want to display in the CustomCell.

Problem: I don't see the user control in the column. I think I need to override Paint() method in CustomCell – Any points how can I do that ?

Note – MSDN example of hosting user control is for editing the cell value – where you make your user control visible right where you are editing your cell. I want my user control to render as a normal winform control. This user control shows notifications for the row .. and each row can have different notifications. I want users to be able to click on notification and get more details about it. .. but for now I am stuck at "how do I display this user control"

Any pointers will be highly appreciated.

 public class CustomColumn : DataGridViewColumn {
    public CustomColumn() : base(new CustomeCell()) { }
    public override DataGridViewCell CellTemplate
    {
        get
        {
            return base.CellTemplate;
        }
        set
        {
            // Ensure that the cell used for the template is a CalendarCell.
            if (value != null &&
                !value.GetType().IsAssignableFrom(typeof(CustomeCell)))
            {
                throw new InvalidCastException("It should be a custom Cell");
            }
            base.CellTemplate = value;
        }
    }
}
public class CustomeCell : DataGridViewTextBoxCell
{
    public CustomeCell() : base() { }
    public override Type ValueType
    {
        get
        {
            return typeof(CustomUserControl);
        }
    }
    public override Type FormattedValueType
    {
        get
        {
            return typeof(CustomUserControl);
        }
    }
}

Best Solution

First Try: I tried to place a user control on the grid where I needed. Problem: Scrolling the data grid view requires re arranging all those user controls. Result - Rejected.

Second Try: I constructed a user control and painted it in the appropriate cell. Result - works so far.

I just overrode Paint and OnClick methods of DataGridViewCell in the CustomCell class.

public class CustomeCell : DataGridViewCell
{
    public override Type ValueType
    {
        get { return typeof(CustomUserControl); } 
    }

    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)
    {
        var ctrl = (CustomUserControl) value;
        var img = new Bitmap(cellBounds.Width, cellBounds.Height);
        ctrl.DrawToBitmap(img, new Rectangle(0, 0, ctrl.Width, ctrl.Height));
        graphics.DrawImage(img, cellBounds.Location);
    }

    protected override void OnClick(DataGridViewCellEventArgs e)
    {
        List<InfoObject> objs = DataGridView.DataSource as List<InfoObject>;
        if (objs == null)
            return;
        if (e.RowIndex < 0 || e.RowIndex >= objs.Count)
            return;

        CustomUserControl ctrl = objs[e.RowIndex].Ctrl;
        // Take any action - I will just change the color for now.
        ctrl.BackColor = Color.Red;
        ctrl.Refresh();
        DataGridView.InvalidateCell(e.ColumnIndex, e.RowIndex);
    }
}

The example renders the CustomControl in the CustomCell of CustomColumn ;). When user clicks on the cell, CustomCell's OnClick handles the click. Ideally, I would like to delegate that click to the custom user control CustomControl - which should handle the event as if it was a click on itself (custom user control can internally host multiple controls) - so its little complex there.

public class CustomColumn : DataGridViewColumn
{
    public CustomColumn() : base(new CustomeCell()) { }

    public override DataGridViewCell CellTemplate
    {
        get { return base.CellTemplate; }
        set
        {
            if (value != null && !value.GetType()
                .IsAssignableFrom(typeof (CustomeCell)))
                throw new InvalidCastException("It should be a custom Cell");
            base.CellTemplate = value;
        }
    }
}
Related Question