i want to add an ellipse button and textbox control in current cell of my datagridview. By clicking on ellipse button i want to open a custom calculator and result of it will show in textbox. I have already develop custom calculator. I just want to show ellipse button and textbox control in current selected cell. If i leave a cell, then value of textbox control should assign to cell which has lefted. Following is the screenshot.
You need to create custom EditingControl
, Cell
and Column
classes as described here: http://msdn.microsoft.com/en-us/library/aa730881(v=vs.80).aspx
I've created sample application for you. See download link below.
Contents:
TextButton control
UserControl containing TextBox without border and simple button.
Simple Edit Form
Any simple dialog form, returning DialogResult
.
DataGridViewTextButtonEditingControl class
We need to inherit from our TextButton
control and to implement IDataGridViewEditingControl
interface here.
internal class DataGridViewTextButtonEditingControl : TextButton, IDataGridViewEditingControl
{
public DataGridViewTextButtonEditingControl()
{
InnerTextBox.TextChanged += (o, e) => NotifyDataGridViewOfValueChange();
}
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
Font = dataGridViewCellStyle.Font;
if (dataGridViewCellStyle.BackColor.A < 255)
{
Color opaqueBackColor = Color.FromArgb(255, dataGridViewCellStyle.BackColor);
BackColor = opaqueBackColor;
EditingControlDataGridView.EditingPanel.BackColor = opaqueBackColor;
}
else
{
BackColor = dataGridViewCellStyle.BackColor;
}
ForeColor = dataGridViewCellStyle.ForeColor;
}
public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)
{
TextBox textBox = InnerTextBox;
switch (keyData & Keys.KeyCode)
{
case Keys.Right:
{
if (textBox != null)
{
// If the end of the selection is at the end of the string,
// let the DataGridView treat the key message
if ((RightToLeft == RightToLeft.No && !(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length)) ||
(RightToLeft == RightToLeft.Yes && !(textBox.SelectionLength == 0 && textBox.SelectionStart == 0)))
{
return true;
}
}
break;
}
case Keys.Left:
{
if (textBox != null)
{
// If the end of the selection is at the begining of the string
// or if the entire text is selected and we did not start editing,
// send this character to the dataGridView, else process the key message
if ((RightToLeft == RightToLeft.No && !(textBox.SelectionLength == 0 && textBox.SelectionStart == 0)) ||
(RightToLeft == RightToLeft.Yes && !(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length)))
{
return true;
}
}
break;
}
case Keys.Home:
case Keys.End:
{
// Let the grid handle the key if the entire text is selected.
if (textBox != null)
{
if (textBox.SelectionLength != textBox.Text.Length)
{
return true;
}
}
break;
}
case Keys.Delete:
{
// Let the grid handle the key if the carret is at the end of the text.
if (textBox != null)
{
if (textBox.SelectionLength > 0 ||
textBox.SelectionStart < textBox.Text.Length)
{
return true;
}
}
break;
}
}
return !dataGridViewWantsInputKey;
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return Text; // Convert.ChangeType(Text, typeof(int));
}
public void PrepareEditingControlForEdit(bool selectAll)
{
if (selectAll)
{
InnerTextBox.SelectAll();
}
else
{
// Do not select all the text, but
// position the caret at the end of the text
InnerTextBox.SelectionStart = InnerTextBox.Text.Length;
}
}
public DataGridView EditingControlDataGridView { get; set; }
public object EditingControlFormattedValue { get; set; }
public int EditingControlRowIndex { get; set; }
public bool EditingControlValueChanged { get; set; }
public Cursor EditingPanelCursor { get; private set; }
public bool RepositionEditingControlOnValueChange { get; private set; }
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
NotifyDataGridViewOfValueChange();
}
private void NotifyDataGridViewOfValueChange()
{
if (!EditingControlValueChanged)
{
EditingControlValueChanged = true;
EditingControlDataGridView.NotifyCurrentCellDirty(true);
}
}
}
DataGridViewTextButtonCell class
We need to inherit from the DataGridViewCell
to implement DataGridViewTextButtonEditingControl
initialization, cell painting and (important!) cloning.
Without overriding the Clone()
method, we will not be able to set properties of a newly created instances.
internal sealed class DataGridViewTextButtonCell : DataGridViewCell
{
private const byte DATAGRIDVIEWTEXTBOXCELL_horizontalTextOffsetLeft = 3;
private const byte DATAGRIDVIEWTEXTBOXCELL_horizontalTextOffsetRight = 4;
private const byte DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft = 0;
private const byte DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginRight = 0;
private const byte DATAGRIDVIEWTEXTBOXCELL_verticalTextOffsetTop = 2;
private const byte DATAGRIDVIEWTEXTBOXCELL_verticalTextOffsetBottom = 1;
private const byte DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithWrapping = 1;
private const byte DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithoutWrapping = 2;
private const byte DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginBottom = 1;
// Type of this cell's editing control
private static readonly Type defaultEditType = typeof(DataGridViewTextButtonEditingControl);
// Type of this cell's value. The formatted value type is string, the same as the base class DataGridViewTextBoxCell
private static readonly Type defaultValueType = typeof(string);
public override object Clone()
{
DataGridViewTextButtonCell cell = base.Clone() as DataGridViewTextButtonCell;
if (cell != null)
{
cell.ButtonClickHandler = ButtonClickHandler;
}
return cell;
}
/// <summary>
/// Adjusts the location and size of the editing control given the alignment characteristics of the cell
/// </summary>
private Rectangle GetAdjustedEditingControlBounds(Rectangle editingControlBounds, DataGridViewCellStyle cellStyle)
{
// Add a 1 pixel padding on the left and right of the editing control
editingControlBounds.X += 1;
editingControlBounds.Width = Math.Max(0, editingControlBounds.Width - 2);
// Adjust the vertical location of the editing control:
int preferredHeight = cellStyle.Font.Height + 3;
if (preferredHeight < editingControlBounds.Height)
{
switch (cellStyle.Alignment)
{
case DataGridViewContentAlignment.MiddleLeft:
case DataGridViewContentAlignment.MiddleCenter:
case DataGridViewContentAlignment.MiddleRight:
editingControlBounds.Y += (editingControlBounds.Height - preferredHeight) / 2;
break;
case DataGridViewContentAlignment.BottomLeft:
case DataGridViewContentAlignment.BottomCenter:
case DataGridViewContentAlignment.BottomRight:
editingControlBounds.Y += editingControlBounds.Height - preferredHeight;
break;
}
}
return editingControlBounds;
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
TextButton textButton = DataGridView.EditingControl as TextButton;
if (textButton != null)
{
//textButton.BorderStyle = BorderStyle.None;
string initialFormattedValueStr = initialFormattedValue as string;
textButton.Text = initialFormattedValueStr;
if (ButtonClickHandler != null)
textButton.ButtonClick += ButtonClickHandler;
}
}
public override void DetachEditingControl()
{
base.DetachEditingControl();
TextButton textButton = DataGridView.EditingControl as TextButton;
if (textButton != null)
{
textButton.ClearUndo();
if (ButtonClickHandler != null)
textButton.ButtonClick -= ButtonClickHandler;
}
}
public override void PositionEditingControl(bool setLocation, bool setSize, Rectangle cellBounds, Rectangle cellClip, DataGridViewCellStyle cellStyle, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded, bool isFirstDisplayedColumn, bool isFirstDisplayedRow)
{
Rectangle editingControlBounds = PositionEditingPanel(cellBounds,
cellClip,
cellStyle,
singleVerticalBorderAdded,
singleHorizontalBorderAdded,
isFirstDisplayedColumn,
isFirstDisplayedRow);
editingControlBounds = GetAdjustedEditingControlBounds(editingControlBounds, cellStyle);
DataGridView.EditingControl.Location = new Point(editingControlBounds.X, editingControlBounds.Y);
DataGridView.EditingControl.Size = new Size(editingControlBounds.Width, editingControlBounds.Height);
}
public DataGridViewTextButtonEditingControl EditingControl
{
get { return DataGridView == null ? null : DataGridView.EditingControl as DataGridViewTextButtonEditingControl; }
}
public override Type EditType
{
get { return defaultEditType; }
}
public override Type ValueType
{
get { return base.ValueType ?? defaultValueType; }
}
public override Type FormattedValueType
{
get { return defaultValueType; }
}
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 (DataGridView == null)
{
return;
}
// First paint the borders and background of the cell.
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle,
paintParts & ~(DataGridViewPaintParts.ErrorIcon | DataGridViewPaintParts.ContentForeground));
//if (PartPainted(paintParts, DataGridViewPaintParts.Border))
// PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
Point ptCurrentCell = DataGridView.CurrentCellAddress;
bool cellCurrent = ptCurrentCell.X == ColumnIndex && ptCurrentCell.Y == rowIndex;
bool cellEdited = cellCurrent && DataGridView.EditingControl != null;
// If the cell is in editing mode, there is nothing else to paint
if (cellEdited)
{
if (PartPainted(paintParts, DataGridViewPaintParts.Background))
{
//graphics.FillRectangle(br, cellBounds);
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
}
else
{
if (PartPainted(paintParts, DataGridViewPaintParts.ContentForeground))
{
// Take the borders into account
Rectangle borderWidths = BorderWidths(advancedBorderStyle);
Rectangle valBounds = cellBounds;
valBounds.Offset(borderWidths.X, borderWidths.Y);
valBounds.Width -= borderWidths.Right;
valBounds.Height -= borderWidths.Bottom;
// Also take the padding into account
if (cellStyle.Padding != Padding.Empty)
{
if (DataGridView.RightToLeft == RightToLeft.Yes)
{
valBounds.Offset(cellStyle.Padding.Right, cellStyle.Padding.Top);
}
else
{
valBounds.Offset(cellStyle.Padding.Left, cellStyle.Padding.Top);
}
valBounds.Width -= cellStyle.Padding.Horizontal;
valBounds.Height -= cellStyle.Padding.Vertical;
}
valBounds = GetAdjustedEditingControlBounds(valBounds, cellStyle);
TextFormatFlags horAlign = TextFormatFlags.Left;
switch (cellStyle.Alignment)
{
case DataGridViewContentAlignment.BottomLeft:
case DataGridViewContentAlignment.MiddleLeft:
case DataGridViewContentAlignment.TopLeft:
horAlign = TextFormatFlags.Left;
break;
case DataGridViewContentAlignment.BottomCenter:
case DataGridViewContentAlignment.MiddleCenter:
case DataGridViewContentAlignment.TopCenter:
horAlign = TextFormatFlags.HorizontalCenter;
break;
case DataGridViewContentAlignment.BottomRight:
case DataGridViewContentAlignment.MiddleRight:
case DataGridViewContentAlignment.TopRight:
horAlign = TextFormatFlags.Right;
break;
}
bool cellSelected = (cellState & DataGridViewElementStates.Selected) != 0;
SolidBrush br = new SolidBrush(cellSelected ? cellStyle.SelectionBackColor : cellStyle.BackColor);
if (PartPainted(paintParts, DataGridViewPaintParts.Background))
{
graphics.FillRectangle(br, cellBounds);
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
if (cellStyle.Padding != Padding.Empty)
{
valBounds.Offset(cellStyle.Padding.Left, cellStyle.Padding.Top);
valBounds.Width -= cellStyle.Padding.Horizontal;
valBounds.Height -= cellStyle.Padding.Vertical;
}
if (cellCurrent)
{
// Draw focus rectangle
if (DataGridView.Focused && valBounds.Width > 0 && valBounds.Height > 0)
{
ControlPaint.DrawFocusRectangle(graphics, valBounds, Color.Empty, br.Color);
}
}
int verticalTextMarginTop = cellStyle.WrapMode == DataGridViewTriState.True ? DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithWrapping : DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithoutWrapping;
valBounds.Offset(DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft, verticalTextMarginTop);
valBounds.Width -= DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft + DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginRight;
valBounds.Height -= verticalTextMarginTop + DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginBottom;
TextRenderer.DrawText(graphics, formattedValue as string, cellStyle.Font,
valBounds,
cellSelected ? cellStyle.SelectionForeColor : cellStyle.ForeColor, TextFormatFlags.Default | horAlign | TextFormatFlags.Top);
}
if (PartPainted(paintParts, DataGridViewPaintParts.ErrorIcon))
{
// Paint the potential error icon on top of the NumericUpDown control
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText,
cellStyle, advancedBorderStyle, DataGridViewPaintParts.ErrorIcon);
}
}
}
/// <summary>
/// Little utility function called by the Paint function to see if a particular part needs to be painted.
/// </summary>
private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart)
{
return (paintParts & paintPart) != 0;
}
public EventHandler<TextButton.TextButtonEventArgs> ButtonClickHandler { get; set; }
}
DataGridViewTextButtonColumn class
Simply inherit from the DataGridViewColumn
and provide several properties that should be passed to the our underlying TextButton
control.
internal sealed class DataGridViewTextButtonColumn : DataGridViewColumn
{
private EventHandler<TextButton.TextButtonEventArgs> buttonClickHandler;
public DataGridViewTextButtonColumn()
: base(new DataGridViewTextButtonCell())
{
}
public EventHandler<TextButton.TextButtonEventArgs> ButtonClickHandler
{
get
{
return buttonClickHandler;
}
set
{
DataGridViewTextButtonCell cell = CellTemplate as DataGridViewTextButtonCell;
if (cell != null)
{
if (value != null)
cell.ButtonClickHandler += value;
else if (buttonClickHandler != null)
cell.ButtonClickHandler -= buttonClickHandler;
}
buttonClickHandler = value;
}
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
base.CellTemplate = value;
DataGridViewTextButtonCell cell = CellTemplate as DataGridViewTextButtonCell;
if (cell != null)
cell.ButtonClickHandler = ButtonClickHandler;
}
}
}
Usage example
Assuming that grid
is DataGridView
.
grid.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn
{
ValueType = typeof (string),
HeaderText = "Name"
},
new DataGridViewTextButtonColumn
{
ValueType = typeof (int),
HeaderText = "Count",
ButtonClickHandler = (o, e) =>
{
grid.EndEdit();
using (EditForm frm = new EditForm { Value = e.Text })
if (frm.ShowDialog(this) == DialogResult.OK)
{
e.Text = frm.Value;
e.Handled = true;
}
grid.BeginEdit(false);
}
}
});
Download Link: Full project (Zip-Archive, Target Framework: v.3.5)
UPDATE (10 oct 21): link fixed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With