Button Inside a Winforms Textbox

Button inside a WinForms textbox

Getting the button inside the TextBox just requires adding it to the box' Controls collection. You'll also need to do something reasonable to prevent the text inside the box disappearing underneath the button; that requires a wee bit of pinvoke. Like this:

    protected override void OnLoad(EventArgs e) {
var btn = new Button();
btn.Size = new Size(25, textBox1.ClientSize.Height + 2);
btn.Location = new Point(textBox1.ClientSize.Width - btn.Width, -1);
btn.Cursor = Cursors.Default;
btn.Image = Properties.Resources.star;
textBox1.Controls.Add(btn);
// Send EM_SETMARGINS to prevent text from disappearing underneath the button
SendMessage(textBox1.Handle, 0xd3, (IntPtr)2, (IntPtr)(btn.Width << 16));
base.OnLoad(e);
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

Looked like this while I tested the right margin (should have picked a prettier bitmap):

Sample Image

Button inside a winforms textbox vb.net

It looks like some of the code related to Size and Location is wrong. Try this:

    btn.Size = New Size(25, textBox1.ClientSize.Height + 2)
btn.Location = New Point(textBox1.ClientSize.Width - btn.Width - 1, -1)
btn.FlatStyle = FlatStyle.Flat
btn.Cursor = Cursors.Default
btn.Image = Image.FromFile("C:\ansoft\Soljica\texture\tone.png")
btn.FlatAppearance.BorderSize = 0
textBox1.Controls.Add(btn)
SendMessage(textBox1.Handle, &HD3, CType(2, IntPtr), CType((btn.Width << 16), IntPtr))

How to add button to textbox?

You have to tell the designer that it should also serialize the properties of the button:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Button Button {
//...
}

The default is Hidden so none of the button properties would be written to the Designer.cs file. Setting, say, the Text property works in the designer but the property value is lost after you start the app or reload the form.

How to set focus on textbox and button simultaneously in WinForm

This is a fundamental Windows principle. It's not possible to have 2 controls (windows) focused at the same time.

So the focus should be inside the text box. But you can get the visual indication needed by setting the ok button as AcceptButton of the form (you might also want to set cancel button as CancelButton).

In the form constructor, load event or using designer:

this.AcceptButton = okButton;

There is no need to handle KeyDown event - as soon as the text box is not multiline, pressing Enter while the focus is inside it will generate ok button click. The same applies for the button set as CancelButton when you press ESC.

Winform copy button text to textbox using universal method

You can use this which is more universal as the Control class contains the Text property. Also, using the best practice $"".

private void btn_A_Click(object sender, EventArgs e)
{
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";
}

You can also assign the same event to each button. Create an event, say addControlTextOnClick and assign the same event to each button.

Sample Image

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void addControlTextOnClick(object sender, EventArgs e)
{
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";
}
}

You can even shorten this more using this C# construct:

private void addControlTextOnClick(object sender, EventArgs e) =>
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";

Sample Image

Focusing on textBox after clicking a button

Instead of just using .Focus() go for this combination:

// Set focus to control
txtbox.Focus();
// Set text-selection to end
txtbox.SelectionStart = txtbox.Text.Length == 0 ? 0 : txtbox.Text.Length -1;
// Set text-selection length (in your case 0 = no blue text)
txtbox.SelectionLength = 0

OR

// Set focus to control
txtbox.Focus();

// Check if text is longer then 0
if(txtbox.Text.Length > 0)
{
// Set text-selection to end
txtbox.SelectionStart = txtbox.Text.Length -1;
// Set text-selection length (in your case 0 = no blue text)
txtbox.SelectionLength = 0
}

Both ways are the same. In the first one, I check for text-length == 0 in-place in the second line.

In the second one, I use a classical if statement.

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

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.

    Sample Image

  • Simple Edit Form

    Any simple dialog form, returning DialogResult.

    Sample Image

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



Related Topics



Leave a reply



Submit