您需要按照此处描述的方式创建自定义的EditingControl
、Cell
和Column
类:http://msdn.microsoft.com/en-us/library/aa730881(v=vs.80).aspx
我已经为您创建了示例应用程序。请查看下面的下载链接。
内容如下:
TextButton 控件
包含没有边框和简单按钮的文本框的用户控件。
简单的Edit Form
任何简单的对话框,返回DialogResult
。
DataGridViewTextButtonEditingControl 类
我们需要从我们的TextButton
控件继承,并在此处实现IDataGridViewEditingControl
接口。
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类
我们需要继承自DataGridViewCell
以实现DataGridViewTextButtonEditingControl
的初始化、单元格绘制和(重要的!)克隆。
如果没有重写Clone()
方法,我们将无法设置新创建实例的属性。
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类
只需从DataGridViewColumn
派生,提供应传递给我们的底层TextButton
控件的几个属性。
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;
}
}
}
使用示例
假设grid
是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);
}
}
});
下载链接:完整项目(Zip-Archive,目标框架:v.3.5)
更新 (10月21日):修复了链接。
您需要实现一个自定义控件,该控件实现IDataGridViewEditingControl接口。您还应该查看MSDN文章如何在Windows Forms DataGridView单元格中托管控件。
在SO上也有类似的问题: