Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to add ellipse button and textbox in current cell of datagridview in winforms

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.

enter image description here

enter image description here

like image 939
Tikam Sangwani Avatar asked Dec 16 '22 01:12

Tikam Sangwani


1 Answers

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.
    enter image description here

  • Simple Edit Form
    Any simple dialog form, returning DialogResult.
    enter image description here

  • 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.

like image 51
Dmitry Avatar answered Jan 04 '23 23:01

Dmitry