11

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);
        }
    }
}
karephul
  • 1,473
  • 4
  • 19
  • 36
  • You must also define a class that derives from Control and implements the IDataGridViewEditingControl interface. – Angshuman Agarwal Jun 06 '12 at 19:52
  • @AngshumanAgarwal As I mentioned in my question - I do not want to edit, I just want to display my user control for all the rows in one column. – karephul Jun 06 '12 at 20:10
  • i don't understand exactly..but you want to show a datagridview's not-shown cells' values to the user ?? (i.e. when the user clicked once on a cell) if so, then simply use ToolTip with a SQLQuery or LINQ – sihirbazzz Jun 06 '12 at 21:35

2 Answers2

6

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;
        }
    }
}
Community
  • 1
  • 1
karephul
  • 1,473
  • 4
  • 19
  • 36
1

The DataGridView control only supports displaying an actual control when a cell is in edit mode. The DataGridView control is not designed to display multiple controls or repeat a set of controls per row. The DataGridView control draws a representation of the control when the cell is not being edited. This representation can be a detailed as you want. For example, the DataGridViewButtonCell draws a button regardless of the cell being in edit or not.

However, you can add controls through DataGridView.Controls.Add() method, and set their location and size to make them hosted in the cells, but showing controls in all cells regardless of editing make no sense.

Read here

[Update - From MS DataGridView Team's Prog Mgr]

http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/394e04a8-d918-4fdd-be03-dfa13f6a1e66?persist=True

Angshuman Agarwal
  • 4,796
  • 7
  • 41
  • 89
  • 1
    MS doesn't support something is different - but I don't agree with "but showing controls in all cells regardless of editing make no sense." - Consider you are looking at list of customer orders - each order can have different notifications (no inventory, incomplete address, duplicate order, back ordered .. etc) I would like my users to "view" these notifications - ideally in the column called Notifications ! - without being able to edit them !! - but be able to see more details if they click on one of them. – karephul Jun 06 '12 at 21:30
  • Interesting ! You may read _DataGridView Program Manager's_ comments. I updated the answer with msdn link. – Angshuman Agarwal Jun 06 '12 at 22:05
  • 1
    I don't agree neither with " but showing controls in all cells regardless of editing make no sense." I just found this question because I would like to put a custom button in a cell to do some action on the selected row. If that not make sense to you, why there is a DataGridViewButtonCell ? – tapatio Sep 03 '17 at 03:14