Do WinForms textboxes have any properties that make an embedded button, at the end of the box, possible?
Something like the favorites button on the Chrome address bo
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):
Just a small expansion on the accepted solution, to get the button to look and act properly a few tweaks are needed. Here are tweaks for a search box:
private static readonly int SEARCH_BUTTON_WIDTH = 25;
private void ConfigureSearchBox()
{
var btn = new Button();
btn.Size = new Size(SEARCH_BUTTON_WIDTH, searchBox.ClientSize.Height + 2);
btn.Dock = DockStyle.Right;
btn.Cursor = Cursors.Default;
btn.Image = Properties.Resources.Find_5650;
btn.FlatStyle = FlatStyle.Flat;
btn.ForeColor = Color.White;
btn.FlatAppearance.BorderSize = 0;
btn.Click += btn_Click;
searchBox.Controls.Add(btn);
this.AcceptButton = btn;
// Send EM_SETMARGINS to prevent text from disappearing underneath the button
SendMessage(searchBox.Handle, 0xd3, (IntPtr)2, (IntPtr)(btn.Width << 16));
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private void btn_Click(object sender, EventArgs e)
{
MessageBox.Show("hello world");
}
No. In order to do something like that you need to create your own User Control. It can be easily put together from a text box and button. The difficulty is that if you want similar properties to the text box, you would need to create all them. In the end it is a lot of code.
I saw in Reflector that Control contains "SendMessage(int,int,int)" method and I found another way.
using System;
using System.Reflection;
using System.Windows.Forms;
static class ControlExtensions
{
static BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
static Type[] SendMessageSig = new Type[] { typeof(int), typeof(int), typeof(int) };
internal static IntPtr SendMessage(this Control control, int msg, int wparam, int lparam)
{
MethodInfo MethodInfo = control.GetType().GetMethod("SendMessage", flags, null, SendMessageSig, null);
return (IntPtr)MethodInfo.Invoke(control, new object[] { msg, wparam, lparam });
}
}
Now by overriding WndProc in ButtonTextBox we can achieve desired effect.
public class ButtonTextBox : TextBox
{
Button button;
public ButtonTextBox()
{
this.button = new Button();
this.button.Dock = DockStyle.Right;
this.button.BackColor = SystemColors.Control;
this.button.Width = 21;
this.Controls.Add(this.button);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case 0x30:
int num = this.button.Width + 3;
this.SendMessage(0xd3, 2, num << 16);
return;
}
}
}
And I think this is much safer way.
If you are willing to add a reference to another library, you could consider using the Krypton Toolkit (available at https://github.com/ComponentFactory/Krypton). The basic toolkit that you should be able to use for free (without the ribbons, navigator, or workspace functionality) does allow you to add "button specs" to various controls (including text boxes) which appear visually just as you describe.
A minor addition on the nice idea of Hans Passant - if the textbox is resizable, you could add a binding to the underlying button so that it's Location gets adjusted on ClientSize changes as well:
//Adjust the Location of the button on Size Changes of the containing textBox.
var binding = new Binding("Location", textBox1, "ClientSize");
binding.Format += (s, e) => e.Value = e.Value is Size ? new Point(((Size)e.Value).Width - btn.Width, -1) : new Point(0, 0);
btn.DataBindings.Add(binding);