WinForms文本框中的button

做winforms文本框有任何使embedded式button,在框的结尾可能的属性?

就像Chrome地址栏中的collections夹button一样:

在这里输入图像描述

我在一些Excel表格中也看到了类似下面的内容:

在这里输入图像描述


编辑

我跟着Hans Passant的答案,增加了一个点击事件处理程序,它似乎工作正常:

protected override void OnLoad(EventArgs e) { var btn = new Button(); btn.Size = new Size(25, textBoxFolder.ClientSize.Height + 2); btn.Location = new Point(textBoxFolder.ClientSize.Width - btn.Width, -1); btn.Cursor = Cursors.Default; btn.Image = Properties.Resources.arrow_diagright; btn.Click += btn_Click; textBoxFolder.Controls.Add(btn); // Send EM_SETMARGINS to prevent text from disappearing underneath the button SendMessage(textBoxFolder.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); private void btn_Click(object sender, EventArgs e) { MessageBox.Show("hello world"); } 

获取TextBox中的button只需要将其添加到“Controls集合”框中即可。 你还需要做一些合理的事情,以防止框内的文字消失在button下方; 这需要一点点的努力。 喜欢这个:

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

看起来像这样,而我testing右边距(应select了一个漂亮的位图):

在这里输入图像描述

这是包装在TextBox子类中的答案。

 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); } 

如果你愿意添加一个引用到另一个库,你可以考虑使用氪工具包(可在https://github.com/ComponentFactory/Krypton获得; )。 您应该可以免费使用的基本工具包(不包括function区,导航器或工作区function)允许您将“button规格”添加到按照您描述的方式直观显示的各种控件(包括文本框)。

我在Reflector中看到Control包含“SendMessage(int,int,int)”方法,我find了另一种方法。

 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 }); } } 

现在通过重写ButtonTextBox中的WndProc我们可以达到预期的效果。

 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; } } } 

我认为这是更安全的方法。

Hans Passant的好主意还有一个小小的增加 – 如果文本框可以resize,你可以添加一个绑定到底层的button,这样它的位置就可以在ClientSize变化上调整了:

  //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); 

只是在接受的解决scheme上的一个小的扩展,让button来看看,并采取适当的行动一些调整是必要的。 这里是一个search框的调整:

  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"); } 

不。为了做这样的事情,你需要创build自己的用户控制。 它可以很容易地从一个文本框和button放在一起。 难点在于,如果您想要与文本框相似的属性,则需要创build所有这些属性。 最后是很多代码。

我得到了这个创build。 这是一个具有文本框和button的用户控件。