add custom DataGridViewColumn with label and button per cell











up vote
1
down vote

favorite












I want to add a custom DataGridViewColumn to my DataGridView. This column should create the following cell per row



img



At first I created a custom UserControl that creates a label with a button.



    private class AllocationControl : UserControl
{
public AllocationControl(IndexField indexFields, BatchField batchFields)
{
Label lbl = new Label();
Controls.Add(lbl);

ContextMenuStrip contextMenu = new ContextMenuStrip();
// fill the menu
Controls.Add(contextMenu);

Button btn = new Button();
btn.Click += (object sender, EventArgs e) =>
{
contextMenu.Show(Cursor.Position);
};
Controls.Add(btn);
}

public string DisplayedName { get; private set; }
public double SelectedID { get; private set; }
}


I have to pass in some data as constructor parameters but this is not relevant for the question.



After that I create a custom DataGridViewCell



    private class DataGridViewAllocationCell : DataGridViewCell
{
public DataGridViewAllocationCell()
{
}

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)
{
AllocationControl allocationControl = value as AllocationControl;
Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);
allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));
graphics.DrawImage(allocationControlImage, cellBounds.Location);
}
}


This cell should keep the custom control and display it.



At the end I add this cell to my custom DataGridViewColumn by setting the CellTemplate



    private class DataGridViewAllocationColumn : DataGridViewColumn
{
public DataGridViewAllocationColumn()
{
CellTemplate = new DataGridViewAllocationCell();
}
}


My question is how can I assign the UserControl to the DataGridViewCell?



I took this guide



https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells



but they all show up how to create a single control and put it into a cell. I have to setup three controls (label, button and contextMenu) within one cell.










share|improve this question
























  • You really need to use DataGridView? You can use other Containers for that, it would be easier
    – Pancabiel
    Nov 8 at 11:24












  • yes, I need to display it in a DataGridViewColumn
    – MHComputech
    Nov 8 at 11:44






  • 1




    Isn't an UserControl type of a Control? whats the difference for you?
    – S.Serpooshan
    Nov 12 at 8:12










  • You always can make three columns looks like one...
    – Fabio
    Nov 12 at 8:18










  • Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
    – Ivan Stoev
    Nov 12 at 8:49















up vote
1
down vote

favorite












I want to add a custom DataGridViewColumn to my DataGridView. This column should create the following cell per row



img



At first I created a custom UserControl that creates a label with a button.



    private class AllocationControl : UserControl
{
public AllocationControl(IndexField indexFields, BatchField batchFields)
{
Label lbl = new Label();
Controls.Add(lbl);

ContextMenuStrip contextMenu = new ContextMenuStrip();
// fill the menu
Controls.Add(contextMenu);

Button btn = new Button();
btn.Click += (object sender, EventArgs e) =>
{
contextMenu.Show(Cursor.Position);
};
Controls.Add(btn);
}

public string DisplayedName { get; private set; }
public double SelectedID { get; private set; }
}


I have to pass in some data as constructor parameters but this is not relevant for the question.



After that I create a custom DataGridViewCell



    private class DataGridViewAllocationCell : DataGridViewCell
{
public DataGridViewAllocationCell()
{
}

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)
{
AllocationControl allocationControl = value as AllocationControl;
Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);
allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));
graphics.DrawImage(allocationControlImage, cellBounds.Location);
}
}


This cell should keep the custom control and display it.



At the end I add this cell to my custom DataGridViewColumn by setting the CellTemplate



    private class DataGridViewAllocationColumn : DataGridViewColumn
{
public DataGridViewAllocationColumn()
{
CellTemplate = new DataGridViewAllocationCell();
}
}


My question is how can I assign the UserControl to the DataGridViewCell?



I took this guide



https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells



but they all show up how to create a single control and put it into a cell. I have to setup three controls (label, button and contextMenu) within one cell.










share|improve this question
























  • You really need to use DataGridView? You can use other Containers for that, it would be easier
    – Pancabiel
    Nov 8 at 11:24












  • yes, I need to display it in a DataGridViewColumn
    – MHComputech
    Nov 8 at 11:44






  • 1




    Isn't an UserControl type of a Control? whats the difference for you?
    – S.Serpooshan
    Nov 12 at 8:12










  • You always can make three columns looks like one...
    – Fabio
    Nov 12 at 8:18










  • Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
    – Ivan Stoev
    Nov 12 at 8:49













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I want to add a custom DataGridViewColumn to my DataGridView. This column should create the following cell per row



img



At first I created a custom UserControl that creates a label with a button.



    private class AllocationControl : UserControl
{
public AllocationControl(IndexField indexFields, BatchField batchFields)
{
Label lbl = new Label();
Controls.Add(lbl);

ContextMenuStrip contextMenu = new ContextMenuStrip();
// fill the menu
Controls.Add(contextMenu);

Button btn = new Button();
btn.Click += (object sender, EventArgs e) =>
{
contextMenu.Show(Cursor.Position);
};
Controls.Add(btn);
}

public string DisplayedName { get; private set; }
public double SelectedID { get; private set; }
}


I have to pass in some data as constructor parameters but this is not relevant for the question.



After that I create a custom DataGridViewCell



    private class DataGridViewAllocationCell : DataGridViewCell
{
public DataGridViewAllocationCell()
{
}

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)
{
AllocationControl allocationControl = value as AllocationControl;
Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);
allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));
graphics.DrawImage(allocationControlImage, cellBounds.Location);
}
}


This cell should keep the custom control and display it.



At the end I add this cell to my custom DataGridViewColumn by setting the CellTemplate



    private class DataGridViewAllocationColumn : DataGridViewColumn
{
public DataGridViewAllocationColumn()
{
CellTemplate = new DataGridViewAllocationCell();
}
}


My question is how can I assign the UserControl to the DataGridViewCell?



I took this guide



https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells



but they all show up how to create a single control and put it into a cell. I have to setup three controls (label, button and contextMenu) within one cell.










share|improve this question















I want to add a custom DataGridViewColumn to my DataGridView. This column should create the following cell per row



img



At first I created a custom UserControl that creates a label with a button.



    private class AllocationControl : UserControl
{
public AllocationControl(IndexField indexFields, BatchField batchFields)
{
Label lbl = new Label();
Controls.Add(lbl);

ContextMenuStrip contextMenu = new ContextMenuStrip();
// fill the menu
Controls.Add(contextMenu);

Button btn = new Button();
btn.Click += (object sender, EventArgs e) =>
{
contextMenu.Show(Cursor.Position);
};
Controls.Add(btn);
}

public string DisplayedName { get; private set; }
public double SelectedID { get; private set; }
}


I have to pass in some data as constructor parameters but this is not relevant for the question.



After that I create a custom DataGridViewCell



    private class DataGridViewAllocationCell : DataGridViewCell
{
public DataGridViewAllocationCell()
{
}

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)
{
AllocationControl allocationControl = value as AllocationControl;
Bitmap allocationControlImage = new Bitmap(cellBounds.Width, cellBounds.Height);
allocationControl.DrawToBitmap(allocationControlImage, new Rectangle(0, 0, allocationControl.Width, allocationControl.Height));
graphics.DrawImage(allocationControlImage, cellBounds.Location);
}
}


This cell should keep the custom control and display it.



At the end I add this cell to my custom DataGridViewColumn by setting the CellTemplate



    private class DataGridViewAllocationColumn : DataGridViewColumn
{
public DataGridViewAllocationColumn()
{
CellTemplate = new DataGridViewAllocationCell();
}
}


My question is how can I assign the UserControl to the DataGridViewCell?



I took this guide



https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-host-controls-in-windows-forms-datagridview-cells



but they all show up how to create a single control and put it into a cell. I have to setup three controls (label, button and contextMenu) within one cell.







c# winforms






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 8 at 12:36

























asked Nov 8 at 11:02









MHComputech

31213




31213












  • You really need to use DataGridView? You can use other Containers for that, it would be easier
    – Pancabiel
    Nov 8 at 11:24












  • yes, I need to display it in a DataGridViewColumn
    – MHComputech
    Nov 8 at 11:44






  • 1




    Isn't an UserControl type of a Control? whats the difference for you?
    – S.Serpooshan
    Nov 12 at 8:12










  • You always can make three columns looks like one...
    – Fabio
    Nov 12 at 8:18










  • Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
    – Ivan Stoev
    Nov 12 at 8:49


















  • You really need to use DataGridView? You can use other Containers for that, it would be easier
    – Pancabiel
    Nov 8 at 11:24












  • yes, I need to display it in a DataGridViewColumn
    – MHComputech
    Nov 8 at 11:44






  • 1




    Isn't an UserControl type of a Control? whats the difference for you?
    – S.Serpooshan
    Nov 12 at 8:12










  • You always can make three columns looks like one...
    – Fabio
    Nov 12 at 8:18










  • Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
    – Ivan Stoev
    Nov 12 at 8:49
















You really need to use DataGridView? You can use other Containers for that, it would be easier
– Pancabiel
Nov 8 at 11:24






You really need to use DataGridView? You can use other Containers for that, it would be easier
– Pancabiel
Nov 8 at 11:24














yes, I need to display it in a DataGridViewColumn
– MHComputech
Nov 8 at 11:44




yes, I need to display it in a DataGridViewColumn
– MHComputech
Nov 8 at 11:44




1




1




Isn't an UserControl type of a Control? whats the difference for you?
– S.Serpooshan
Nov 12 at 8:12




Isn't an UserControl type of a Control? whats the difference for you?
– S.Serpooshan
Nov 12 at 8:12












You always can make three columns looks like one...
– Fabio
Nov 12 at 8:18




You always can make three columns looks like one...
– Fabio
Nov 12 at 8:18












Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
– Ivan Stoev
Nov 12 at 8:49




Well, the guide from the link shows what you need to do. Your AllocationControl is a single control, what is inside it (the inner controls) doesn't matter from the DataGridView point of view.
– Ivan Stoev
Nov 12 at 8:49












1 Answer
1






active

oldest

votes

















up vote
1
down vote



accepted
+100










There are 3 main pillars for a new column type:





  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.


  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).


  • DataGridViewEditingControl is responsible for editing the value of the cell.


When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.



Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.



Example



Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:



enter image description here



The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.




Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu
or anything else. But I think it's a good start point.




Here is the code:



using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
public DataGridViewAllocationControlColumn()
{
this.CellTemplate = new DataGridViewAllocationControlCell();
}
public string LabelText { get; set; }
public string ButtonText { get; set; }
public override object Clone()
{
var c = (DataGridViewAllocationControlColumn)base.Clone();
c.LabelText = this.LabelText;
c.ButtonText = this.ButtonText;
return c;
}
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All &
~DataGridViewPaintParts.ContentBackground &
~DataGridViewPaintParts.ContentForeground);
var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
var r2 = GetContentBounds(rowIndex);
var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
r2.Offset(r1.Location);
base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All);
TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
r3, cellStyle.ForeColor);
}
protected override Rectangle GetContentBounds(Graphics graphics,
DataGridViewCellStyle cellStyle, int rowIndex)
{
var w = GetLabelWidth();
var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
}
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var r1 = GetContentBounds(e.RowIndex);
var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
if (c.ContextMenuStrip != null)
c.ContextMenuStrip.Show(g, p);
}
private int GetLabelWidth()
{
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var text = c.LabelText;
return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
}
}





share|improve this answer























  • would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
    – MHComputech
    Nov 13 at 13:11










  • In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
    – Reza Aghaei
    Nov 13 at 13:16










  • I also edited the post to add a short introduction about main pillars of a custom column.
    – Reza Aghaei
    Nov 13 at 13:17











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53206409%2fadd-custom-datagridviewcolumn-with-label-and-button-per-cell%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
1
down vote



accepted
+100










There are 3 main pillars for a new column type:





  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.


  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).


  • DataGridViewEditingControl is responsible for editing the value of the cell.


When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.



Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.



Example



Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:



enter image description here



The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.




Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu
or anything else. But I think it's a good start point.




Here is the code:



using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
public DataGridViewAllocationControlColumn()
{
this.CellTemplate = new DataGridViewAllocationControlCell();
}
public string LabelText { get; set; }
public string ButtonText { get; set; }
public override object Clone()
{
var c = (DataGridViewAllocationControlColumn)base.Clone();
c.LabelText = this.LabelText;
c.ButtonText = this.ButtonText;
return c;
}
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All &
~DataGridViewPaintParts.ContentBackground &
~DataGridViewPaintParts.ContentForeground);
var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
var r2 = GetContentBounds(rowIndex);
var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
r2.Offset(r1.Location);
base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All);
TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
r3, cellStyle.ForeColor);
}
protected override Rectangle GetContentBounds(Graphics graphics,
DataGridViewCellStyle cellStyle, int rowIndex)
{
var w = GetLabelWidth();
var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
}
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var r1 = GetContentBounds(e.RowIndex);
var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
if (c.ContextMenuStrip != null)
c.ContextMenuStrip.Show(g, p);
}
private int GetLabelWidth()
{
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var text = c.LabelText;
return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
}
}





share|improve this answer























  • would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
    – MHComputech
    Nov 13 at 13:11










  • In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
    – Reza Aghaei
    Nov 13 at 13:16










  • I also edited the post to add a short introduction about main pillars of a custom column.
    – Reza Aghaei
    Nov 13 at 13:17















up vote
1
down vote



accepted
+100










There are 3 main pillars for a new column type:





  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.


  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).


  • DataGridViewEditingControl is responsible for editing the value of the cell.


When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.



Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.



Example



Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:



enter image description here



The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.




Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu
or anything else. But I think it's a good start point.




Here is the code:



using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
public DataGridViewAllocationControlColumn()
{
this.CellTemplate = new DataGridViewAllocationControlCell();
}
public string LabelText { get; set; }
public string ButtonText { get; set; }
public override object Clone()
{
var c = (DataGridViewAllocationControlColumn)base.Clone();
c.LabelText = this.LabelText;
c.ButtonText = this.ButtonText;
return c;
}
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All &
~DataGridViewPaintParts.ContentBackground &
~DataGridViewPaintParts.ContentForeground);
var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
var r2 = GetContentBounds(rowIndex);
var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
r2.Offset(r1.Location);
base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All);
TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
r3, cellStyle.ForeColor);
}
protected override Rectangle GetContentBounds(Graphics graphics,
DataGridViewCellStyle cellStyle, int rowIndex)
{
var w = GetLabelWidth();
var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
}
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var r1 = GetContentBounds(e.RowIndex);
var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
if (c.ContextMenuStrip != null)
c.ContextMenuStrip.Show(g, p);
}
private int GetLabelWidth()
{
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var text = c.LabelText;
return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
}
}





share|improve this answer























  • would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
    – MHComputech
    Nov 13 at 13:11










  • In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
    – Reza Aghaei
    Nov 13 at 13:16










  • I also edited the post to add a short introduction about main pillars of a custom column.
    – Reza Aghaei
    Nov 13 at 13:17













up vote
1
down vote



accepted
+100







up vote
1
down vote



accepted
+100




+100




There are 3 main pillars for a new column type:





  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.


  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).


  • DataGridViewEditingControl is responsible for editing the value of the cell.


When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.



Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.



Example



Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:



enter image description here



The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.




Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu
or anything else. But I think it's a good start point.




Here is the code:



using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
public DataGridViewAllocationControlColumn()
{
this.CellTemplate = new DataGridViewAllocationControlCell();
}
public string LabelText { get; set; }
public string ButtonText { get; set; }
public override object Clone()
{
var c = (DataGridViewAllocationControlColumn)base.Clone();
c.LabelText = this.LabelText;
c.ButtonText = this.ButtonText;
return c;
}
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All &
~DataGridViewPaintParts.ContentBackground &
~DataGridViewPaintParts.ContentForeground);
var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
var r2 = GetContentBounds(rowIndex);
var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
r2.Offset(r1.Location);
base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All);
TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
r3, cellStyle.ForeColor);
}
protected override Rectangle GetContentBounds(Graphics graphics,
DataGridViewCellStyle cellStyle, int rowIndex)
{
var w = GetLabelWidth();
var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
}
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var r1 = GetContentBounds(e.RowIndex);
var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
if (c.ContextMenuStrip != null)
c.ContextMenuStrip.Show(g, p);
}
private int GetLabelWidth()
{
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var text = c.LabelText;
return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
}
}





share|improve this answer














There are 3 main pillars for a new column type:





  • DataGridViewColumn is responsible for properties which you set in design mode in column editor of the control.


  • DataGridViewCell is responsible for appearance of the cell. It renders the value and other painting parts in cell and initialize the editing control (if the column has any editing control).


  • DataGridViewEditingControl is responsible for editing the value of the cell.


When creating a new column you can derive from DataGridViewColumn or one of its derived classes. Also when creating a new cell for the column, you can derive from DataGridViewCell or one of its derived classes. Also when creating a new editing control, you can derive from one of the existing editing controls, or you can start by deriving from a control class and implementing IDataGridViewEditingControl interface.



Keep in mind, the editing control will be shown just in the editing cell. Rest of cells show what you render in the paint method of the cell.



Example



Here in this post, I've shared an example of drawing a custom cell containing a label and a button. I've not created an editing control because for this example, we can derive from DataGridViewButtonColumn and DataGridViewButtonCell without needing to create an editing control. We just add some properties to column and change paint logic and override OnContentClick to show the context menu, like this:



enter image description here



The custom column has LabelText and ButtonText properties. When you click on the button part, it shows the ContextMenuStrip which you assigned to corresponding property.




Note: This is just an example and depending on the requirements, you may want to change properties, rendering logic and the way that you show menu
or anything else. But I think it's a good start point.




Here is the code:



using System.Drawing;
using System.Windows.Forms;
public class DataGridViewAllocationControlColumn : DataGridViewButtonColumn
{
public DataGridViewAllocationControlColumn()
{
this.CellTemplate = new DataGridViewAllocationControlCell();
}
public string LabelText { get; set; }
public string ButtonText { get; set; }
public override object Clone()
{
var c = (DataGridViewAllocationControlColumn)base.Clone();
c.LabelText = this.LabelText;
c.ButtonText = this.ButtonText;
return c;
}
}
public class DataGridViewAllocationControlCell : DataGridViewButtonCell
{
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex,
DataGridViewElementStates elementState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All &
~DataGridViewPaintParts.ContentBackground &
~DataGridViewPaintParts.ContentForeground);
var r1 = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
var r2 = GetContentBounds(rowIndex);
var r3 = new Rectangle(r1.Location, new Size(GetLabelWidth(), r1.Height));
r2.Offset(r1.Location);
base.Paint(graphics, clipBounds, r2, rowIndex, elementState,
value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
DataGridViewPaintParts.All);
TextRenderer.DrawText(graphics, c.LabelText, cellStyle.Font,
r3, cellStyle.ForeColor);
}
protected override Rectangle GetContentBounds(Graphics graphics,
DataGridViewCellStyle cellStyle, int rowIndex)
{
var w = GetLabelWidth();
var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
return new Rectangle(r.Left + w, r.Top, r.Width - w, r.Height);
}
protected override void OnContentClick(DataGridViewCellEventArgs e)
{
base.OnContentClick(e);
var g = this.DataGridView;
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var r1 = GetContentBounds(e.RowIndex);
var r2 = g.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, false);
var p = new Point(r2.Left + r1.Left, r2.Top + r1.Bottom);
if (c.ContextMenuStrip != null)
c.ContextMenuStrip.Show(g, p);
}
private int GetLabelWidth()
{
var c = (DataGridViewAllocationControlColumn)this.OwningColumn;
var text = c.LabelText;
return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width;
}
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 13 at 13:37

























answered Nov 13 at 1:17









Reza Aghaei

61.9k849139




61.9k849139












  • would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
    – MHComputech
    Nov 13 at 13:11










  • In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
    – Reza Aghaei
    Nov 13 at 13:16










  • I also edited the post to add a short introduction about main pillars of a custom column.
    – Reza Aghaei
    Nov 13 at 13:17


















  • would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
    – MHComputech
    Nov 13 at 13:11










  • In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
    – Reza Aghaei
    Nov 13 at 13:16










  • I also edited the post to add a short introduction about main pillars of a custom column.
    – Reza Aghaei
    Nov 13 at 13:17
















would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
– MHComputech
Nov 13 at 13:11




would you mind adding the following things: where do setup the context menu? If you setup the LabelText do you change it for all the cells within the column? The LabelText should represent the item I select from the context menu.
– MHComputech
Nov 13 at 13:11












In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
– Reza Aghaei
Nov 13 at 13:16




In this example, I set the label text using a property of column. It means it will be set for all cells. If it should respect to cell value or something, you can simply use Value property of cell, or add a custom property to the cell.
– Reza Aghaei
Nov 13 at 13:16












I also edited the post to add a short introduction about main pillars of a custom column.
– Reza Aghaei
Nov 13 at 13:17




I also edited the post to add a short introduction about main pillars of a custom column.
– Reza Aghaei
Nov 13 at 13:17


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53206409%2fadd-custom-datagridviewcolumn-with-label-and-button-per-cell%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Schultheiß

Verwaltungsgliederung Dänemarks

Liste der Kulturdenkmale in Wilsdruff