Windows Forms have a few column types for DataGridView including DataGridViewTextBoxColumn
, DataGridViewCheckBoxColumn
, DataGridViewComboBoxColumn
, DataGridViewImageColumn
, DataGridViewButtonColumn
and DataGridViewLinkColumn
. You can also create custom columns for DataGridView
by deriving from DataGridViewColumn
or any of mentioned classes and provide a new appearance and behavior for your custom column.
In this post I’m going to show how to create a column type to show and edit passwords, called DataGridViewPasswordColumn
.
Creating Custom Column in DataGridView – Basic Rules
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 rendering the value and initialize the 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.
When creating a custom cell, here are the guidelines that you should follow:
- Your custom cell should have the same properties which the custom column has. Also the editing control should have the same properties.
- In your custom column, in getter of properties, you should get the property value from
CellTemplate
. - In your custom column, in setter of properties, set the property value to
CellTemplate
. Also, im most cases, you neecd to set the property value for all cells of the column using afor
loop, because the user expect column settings apply to all cells. - In your custom cell, you need to override
Clone
and make sure you perform a deep copy of properties of custom cell. But since you store property values in cell template, you don’t need to overrideClone
for custom column. Cloning is important for designer. - In your custom cell, in
InitializeEditingControl
you should setup editing control using properties of the custom cell. Also, in most cases, you need to keep a reference to the editing control, and update properties of the editing control in setter of properties of the cell, because the user expect to see changes on the editing control if a property of column changed. - In your custom editing control, you need to handle the event which is raised by changing value (here in your case
OnTextChanged
) and then notify theDataGridView
that the cell has been dirty usingthis.EditingControlDataGridView.NotifyCurrentCellDirty(true);
You can see the rules which I mentioned in source codes related to ComboBox
column:
Creating DataGridView Password Column
To create a a password column called DataGridViewPasswordColumn
, for the column we can derive from DataGridViewTextBoxColumn
. For the cell we can derive from DataGridViewTextBoxCell
and for the editing control we don’t need to do anything other than configuring the default editing control of the DataGridViewTextBoxCell
.
We need a property called UsePasswordCharWhenEditing
which tells us if we should use the password character when editing the field.
Here is the code for the the column and the cell:
using System.Drawing;
using System.Windows.Forms;
public class DataGridViewPasswordColumn : DataGridViewTextBoxColumn
{
public DataGridViewPasswordColumn()
{
this.CellTemplate = new DataGriViewPasswordCell();
}
private DataGriViewPasswordCell PasswordCellTemplate
{
get { return (DataGriViewPasswordCell)this.CellTemplate; }
}
public bool UsePasswordCharWhenEditing
{
get
{
return PasswordCellTemplate.UsePasswordCharWhenEditing;
}
set
{
if (PasswordCellTemplate != null)
PasswordCellTemplate.UsePasswordCharWhenEditing = value;
if (this.DataGridView != null)
{
var dataGridViewRows = this.DataGridView.Rows;
var rowCount = dataGridViewRows.Count;
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
{
var dataGridViewRow = dataGridViewRows.SharedRow(rowIndex);
var dataGridViewCell = dataGridViewRow.Cells[this.Index]
as DataGriViewPasswordCell;
if (dataGridViewCell != null)
{
dataGridViewCell.UsePasswordCharWhenEditing = value;
}
}
}
}
}
public class DataGriViewPasswordCell : DataGridViewTextBoxCell
{
public DataGriViewPasswordCell()
{
this.UsePasswordCharWhenEditing = true;
}
public bool UsePasswordCharWhenEditing { get; set; }
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue,
DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
((TextBox)this.DataGridView.EditingControl).UseSystemPasswordChar = UsePasswordCharWhenEditing;
}
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)
{
formattedValue = new string('●', $"{formattedValue}".Length);
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts);
}
public override object Clone()
{
var c = (DataGriViewPasswordCell)base.Clone();
c.UsePasswordCharWhenEditing = this.UsePasswordCharWhenEditing;
return c;
}
}
}
Download
You can download the full working example: