如何在winforms中的datagridview的当前单元格中添加椭圆按钮和文本框

我想在我的datagridview的当前单元格中添加一个椭圆按钮和文本框控件。 通过单击椭圆按钮,我想打开一个自定义计算器,它的结果将显示在文本框中。 我已经开发了自定义计算器。 我只想在当前选定的单元格中显示椭圆按钮和文本框控件。 如果我离开一个单元格,那么文本框控件的值应该分配给已经提取的单元格。 以下是截图。

在此处输入图像描述

在此处输入图像描述

您需要创建自定义EditingControlCellColumn类,如下所述: http : //msdn.microsoft.com/en-us/library/aa730881( EditingControl .aspx

我已经为你创建了示例应用程序。 见下面的下载链接。
内容:

  • TextButton控件
    UserControl包含没有边框和简单按钮的TextBox。
    在此处输入图像描述

  • 简单的编辑表格
    任何简单的对话框forms,返回DialogResult
    在此处输入图像描述

  • DataGridViewTextButtonEditingControl
    我们需要从TextButton控件inheritance并在此处实现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
    我们需要从DataGridViewCellinheritance来实现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; } ///  /// Adjusts the location and size of the editing control given the alignment characteristics of the cell ///  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); } } } ///  /// Little utility function called by the Paint function to see if a particular part needs to be painted. ///  private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart) { return (paintParts & paintPart) != 0; } public EventHandler ButtonClickHandler { get; set; } } 
  • DataGridViewTextButtonColumn
    只需从DataGridViewColumninheritance并提供应传递给我们的底层TextButton控件的几个属性。

     internal sealed class DataGridViewTextButtonColumn : DataGridViewColumn { private EventHandler buttonClickHandler; public DataGridViewTextButtonColumn() : base(new DataGridViewTextButtonCell()) { } public EventHandler 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; } } } 
  • 用法示例
    假设gridDataGridView

     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,Target Framework:v.3.5)

您需要实现一个实现IDataGridViewEditingControl接口的自定义控件 。 您还应该查看MSDN文章如何:Windows窗体DataGridView单元中的主机控件 。

在SO上也有类似的问题:

如何在DataGridViewCell中托管控件以进行显示和编辑?