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):

enter image description here


Here's the answer wrapped in a TextBox subclass.

public class ButtonTextBox : TextBox {
    private readonly Button _button;

    public event EventHandler ButtonClick { add { _button.Click += value; } remove { _button.Click -= value; } }

    public ButtonTextBox() {
        _button = new Button {Cursor = Cursors.Default};
        _button.SizeChanged += (o, e) => OnResize(e);
        this.Controls.Add(_button); 
    }

    public Button Button {
        get {
            return _button;
        }
    }

    protected override void OnResize(EventArgs e) {
        base.OnResize(e);
        _button.Size = new Size(_button.Width, this.ClientSize.Height + 2);
        _button.Location = new Point(this.ClientSize.Width - _button.Width, -1);
        // Send EM_SETMARGINS to prevent text from disappearing underneath the button
        SendMessage(this.Handle, 0xd3, (IntPtr)2, (IntPtr)(_button.Width << 16));
    }

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

}

Tags:

C#

.Net

Winforms