2013-04-07 17 views
32

Metin formları, metin kutularının, kutunun sonunda gömülü bir düğme oluşturan herhangi bir özelliği var mı?Bir winform metin kutusunun içindeki düğme

Chrome adres kutusunda sık düğme gibi

şey:

enter image description here


: Ben de bazı Excel formları aşağıdaki gibi bir şey gördüm

enter image description here

EDIT

Ben bir tıklama olay işleyicisi eklenmesiyle Hans passant yanıtını takip ettik ve Tamam çalışmıyor gibi görünüyor: Kendi kullanıcı denetimi oluşturmak için gereken böyle bir şey yapmak için

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

@Highcore, sen umutsuz tek kişilik bir midilli. Lütfen [winforms] etiketini yok sayılan etiketlerinize ekleyin, artık wpf yayınlarınızı görmek istemiyorum. –

+0

@HighCore Hans'ın söylediği şeyden önce size dikkat çektim. Şu andan itibaren WinForms sorularından kaçınmanızı şiddetle tavsiye ederim. –

+0

@HansPassant .... Sadece şimdi ayrılmaktan ve sorularla yetiniyorum - iyi insanlar onu korkutuyor gibi görünüyor! – whytheq

cevap

44

TextBox'un içindeki düğmeyi kullanmak, 'Denetimleri koleksiyon kutusuna eklemeyi gerektirir. Ayrıca kutunun içindeki metnin düğmenin altında kaybolmasını önlemek için makul bir şey yapmanız gerekir; Bu bir iğneli pinvoke gerektirir. Şunun gibi:

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

(daha güzel bir bit eşlem seçmeliydim) Birazdan marjı test bu süre benziyordu:

enter image description here

+0

+1 Teşekkürler Hans - Projemde uygulayıp uygulanmadığını göreceğim; basit görünüyor - bir bitmap bul: proje kaynaklarına içe aktarma; bitmap ismi verin; Kodunuzu yeni adlandırılmış bitmap ile kullanın .... – whytheq

+0

iyi çalışıyor: Ben de bir şey yapması için 'btn.Click + = btn_Click;' satırını ekledim. Bazı iyi kodları mahvedersem% 100 emin olmadığım için OP'yi değiştireceğim. – whytheq

+0

@Hans Passant - Bu harika bir çözüm, teşekkürler. SendMessage işlevinin nasıl çalıştığına dair biraz ayrıntı ekleyebilir misiniz? – JWiley

0

sayılı. Bir metin kutusundan ve düğmesinden kolayca bir araya getirilebilir. Zorluk, metin kutusuna benzer özellikler istiyorsanız, bunların hepsini oluşturmanız gerekir. Sonunda çok fazla kod var.

+0

Bu ikinci ekran baskısı OP'de bir Excel formunda gösterdiğim için orada bir yerde olmalı mı? Bir Excel kütüphanesinden miras alabilir miyim? – whytheq

+1

@whytheq - Excel, Windows API ve MFC kullanılarak C++ ile yazılmıştır. Bu özel bir yazılı kontrol. WinForms'da böyle bir şey yapabilirsiniz, ancak özel kontrol oluşturmanız gerekir. WPF'yi öğrenmeyi öneririm. Bunu yapmak için çok daha kolay – thorkia

+0

@thorkia - excel fikrinin biraz alındığı gibi görünüyor, ancak lütfen Hans çözümünü + yorumları OP'ye göz atın. – whytheq

3

başka kitaplığa bir başvuru eklemek için istekli iseniz, Kripton Toolkit'i kullanmayı düşünebilir (https://github.com/ComponentFactory/Krypton numaralı telefondan edinilebilir). Ücretsiz olarak kullanabilmeniz gereken temel araç seti (şeritler, navigatör veya çalışma alanı işlevselliği olmadan), açıkladığınız gibi görsel olarak görünen çeşitli denetimlere (metin kutuları dahil) "düğme özelliklerini" eklemenize izin verir.

7

İşte bir TextBox alt sınıfında sarılmış yanıt.

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

} 
+0

Bu sürümü ne yazık ki kullanmanın bazı garip yan etkileri var. Örneğin, Buttonton'un Image alanını ButtonTextBox altındaki "Button" üyesini ortaya çıkararak ayarlayabilirsiniz, ancak Debug/Run'ı vurduğunuzda, Düğme görüntüyü "forget" eder ve tasarımcıya geri döner, ayar kaybolur Aynı zamanda ... – MrCC

1

Hans Passant güzel fikri üzerine minör ilave - metin kutusu yeniden boyutlandırılabilir olup olmadığını, bir altta yatan düğmeye bağlanmasını ekleyebilir o Yer ClientSize üzerinde ayarlanır alır belirtilmesi için de değişir:

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

Sadece kabul edilen çözüm üzerinde küçük bir genişleme, düğmenin düzgün bir şekilde görünüp hareket etmesi için birkaç ince ayar yapılması gerekir. İşte arama kutusu için ince ayarlar şunlardır:

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

Ben Denetimi "SendMessage (int, int, int)" yöntemi içerdiğini yansıtıcı içinde gördüm ve başka bir yol buldum.

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

Şimdi ButtonTextBox'ta WndProc'u geçersiz kılarak istenen efekti elde edebiliriz.

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

Ve bence bu daha güvenli bir yol.

+0

Yukarı çözümden yana oy kullandı ancak ne yaptığını merak ettim. Bu numaralar ne anlama geliyor? – Lara

+0

Cevabınız için teşekkür ederiz. 0x0030'un WM_SETFONT mesajı olduğunu biliyorum, ancak neden 2 ve num << 16, wParam yazı tipinin bir tanıtıcısı ve lParam'ın düşük sıralı kelimesi yeniden çizilecek bir boolean olduğunda neden? Ayrıca, şimdi Hans cevabının en iyi olduğunu mu düşünüyorsunuz? Kendine ait bir sınıf benim için daha çok tercih edilir. – Lara

İlgili konular