Кнопка внутри текстового поля WinForms
Есть ли в текстовых полях WinForms какие-либо свойства, которые делают встроенной кнопку в конце поля возможной?
Что-то вроде кнопки "Избранное" в адресной строке Chrome:
![enter image description here]()
Я также видел что-то вроде следующего в некоторых формах Excel:
![enter image description here]()
EDIT
Я последовал за ответом Ханса Пассанта с добавлением обработчика события щелчка, и, похоже, он работает нормально:
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");
}
Ответы
Ответ 1
Получение кнопки внутри TextBox просто требует добавления ее в поле "Коллекция элементов управления". Вам также нужно будет сделать что-то разумное, чтобы текст внутри коробки не исчез под кнопкой; что требует бит-булавки. Вот так:
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);
Похоже на это, когда я тестировал правильный запас (должен был выбрать более красивое растровое изображение):
![enter image description here]()
Ответ 2
Здесь ответ завернут в подкласс 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);
}
Ответ 3
Я видел в Reflector, что Control содержит метод SendMessage (int, int, int), и я нашел другой способ.
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 });
}
}
Теперь, переопределив WndProc в ButtonTextBox, мы сможем добиться желаемого эффекта.
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;
}
}
}
И я думаю, что это намного безопаснее.
Ответ 4
Если вы хотите добавить ссылку на другую библиотеку, вы можете рассмотреть возможность использования инструментария Krypton Toolkit (доступного по адресу https://github.com/ComponentFactory/Krypton). Основной набор инструментов, который вы можете использовать бесплатно (без лент, навигаторов или функций рабочего пространства), позволяет вам добавлять "спецификации кнопок" к различным элементам управления (включая текстовые поля), которые визуально отображаются так же, как вы описываете.
Ответ 5
Просто небольшое расширение принятого решения, чтобы заставить кнопку выглядеть и действовать должным образом, необходимы несколько настроек. Вот настройки для окна поиска:
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");
}
Ответ 6
Нет. Чтобы сделать что-то подобное, вам нужно создать свой собственный User Control. Его можно легко собрать из текстового поля и кнопки. Трудность состоит в том, что если вы хотите, чтобы аналогичные свойства были в текстовом поле, вам нужно было бы создать их все. В конце концов, это много кода.
Ответ 7
Небольшое дополнение к хорошей идее Hans Passant - если текстовое поле можно изменить, вы можете добавить привязку к основной кнопке, чтобы ее местоположение также корректировалось на изменения 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);
Ответ 8
Я получил этот. Это пользовательский элемент управления, который имеет TextBox и Button.