Botão dentro de uma checkbox de texto do winforms

As checkboxs de texto do winforms têm alguma propriedade que possibilite um botão incorporado, no final da checkbox?

Algo como o botão de favoritos na checkbox de endereço do Chrome:

insira a descrição da imagem aqui

Eu também vi algo como o seguinte em alguns formulários do Excel:

insira a descrição da imagem aqui


EDITAR

Eu segui a resposta de Hans Passant com a adição de um manipulador de events click e parece funcionar ok:

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

Obtendo o botão dentro do TextBox apenas requer adicioná-lo à checkbox ‘Controls collection. Você também precisará fazer algo razoável para evitar que o texto dentro da checkbox desapareça embaixo do botão; isso requer um pouquinho de pinvoke. Como isso:

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

Parecia assim enquanto eu testava a margem certa (deveria ter escolhido um bitmap mais bonito):

insira a descrição da imagem aqui

Aqui está a resposta envolvida em uma subclass 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); } 

Se você estiver disposto a adicionar uma referência a outra biblioteca, você pode considerar o uso do Krypton Toolkit (disponível em https://github.com/ComponentFactory/Krypton ). O kit de ferramentas básico que você deve poder usar gratuitamente (sem as funcionalidades de fitas, navegador ou espaço de trabalho) permite adicionar “especificações de botão” a vários controles (incluindo checkboxs de texto) que aparecem visualmente exatamente como você descreve.

Eu vi no Reflector que o controle contém o método “SendMessage (int, int, int)” e eu encontrei uma outra maneira.

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

Agora, substituindo WndProc em ButtonTextBox, podemos alcançar o efeito desejado.

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

E eu acho que isso é muito mais seguro.

Um pequeno acréscimo à boa idéia de Hans Passant – se a checkbox de texto for redimensionável, você pode adicionar uma binding ao botão subjacente para que o Local também seja ajustado nas alterações do 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); 

Apenas uma pequena expansão na solução aceita, para que o botão pareça e funcione corretamente, são necessários alguns ajustes. Aqui estão os ajustes para uma checkbox de pesquisa:

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

Não. Para fazer algo assim, você precisa criar seu próprio controle de usuário. Pode ser facilmente reunido a partir de uma checkbox de texto e botão. A dificuldade é que, se você quiser propriedades semelhantes à checkbox de texto, precisará criar todas elas. No final, é muito código.