none
Textbox Zusatzinfos in die Textbox zeichnen RRS feed

  • Frage

  • Hi,

    Ich hab lange versucht, mittels Überschreibung von OnPaint und setzten von ControlStyles.UserPaint in meiner TextBox-Ableitung etwas in die TextBox zu zeichnen. Aber das scheint wohl so nicht angedacht zu sein.

    Schon alleine durch Setzten von ControlStyles.UserPaint auf true ohne irgendwelche anderen Einflußnamen (Kein Zeichnen keine Events, sozusagen nackte Ableitung) wird die TextBox unbenutzbar. Enthaltene Texte werden erst angezeigt wenn man draufklickt und nur solange man den Mauszeiger über der TextBox hält.

    Hab ich mich nach was anderem umgeschaut und bis letztendlich beim Überschreiben von WndProc und einem eher ungünstigen Hack hängengeblieben.

    protected override void WndProc(ref Message m)
            {
                // Turn off context menu
                if (m.Msg != (int)WindowsMessages.WM_CONTEXTMENU)
                    base.WndProc(ref m);
                // Windows Paint message
                if (m.Msg == (int)WindowsMessages.WM_PAINT)
                {
                    //base.WndProc(ref m);
                    if (!Enabled || Focused || Text != "") return;
                    // Prepare for drawing
                    IntPtr hdc = SafeNativeMethods.GetWindowDC(Handle);
                    Graphics g = Graphics.FromHdc(hdc);
                    g.DrawString("Defaultwert…", Font, Brushes.DarkGray, 5, 2);
                    SafeNativeMethods.ReleaseDC(Handle, hdc);
                }
            }

    Wobei SafeNativeMethods (wie zu sehen) ein paar Interops definiert.

    Der "Trick" ist hier base.WndProc(…) nur aufzurufen wenn keine WM_CONTEXTMENU Message vorliegt. Wenn man das weglässt hängt sich das Programm auf.

    Funktioniert zwar erst mal unter der Auflage das man kein Kontextmenu mehr nutzen kann, aber das kanns ja dann doch nicht sein oder? Außerdem tritt hier das Flackern auf was schon bekannt ist, aber durch OptimizeDoubleBuffer nicht behoben werden kann, da man dazu auch wieder UserPaint auf true setzen muss. Ein Teufelskreis also ;-)

    Kennt dagegen jemand Abhilft oder weis eine bessere Lösung zum zusätzlichen Zeichnen von Text oder Image in eine TextBox?

    Gruß, Ulf

    Donnerstag, 10. Januar 2013 10:30

Antworten

  • Hallo Ulf,

    ich konnte das Problem mit dem Kontextmenü nicht nachvollziehen. Der Code unten ruft zusätzlich zum Selbstgemalten die DefWndProc aufgerufen, damit die Standardroutine ablaufen kann. Auch ein Flackern hält sich in Grenzen, wenn man wie gezeigt den TextRenderer verwendet.

        public class TextBoxWithDefault : System.Windows.Forms.TextBox
        {
            public TextBoxWithDefault() 
            {
            }
    
            const int WM_PAINT = 15;
            
            [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowDC", ExactSpelling = true)]
            private static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "ReleaseDC", ExactSpelling = true)]
            private static extern int ReleaseDC(IntPtr hWnd, HandleRef hDC);
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_PAINT)
                {
                    if (!String.IsNullOrEmpty(base.Text) || !base.Enabled || base.Focused)
                    {
                        base.WndProc(ref m);
                    }
                    else
                    {
                        base.DefWndProc(ref m);
                        var hDC = new HandleRef(this, GetWindowDC(this.Handle));
                        try
                        {
                            Debug.WriteLine("TextBoxWithDefault Standardtext");
                            using (Graphics g = Graphics.FromHdcInternal(hDC.Handle))
                            {
                                TextRenderer.DrawText(g, "Standard", base.Font, base.ClientRectangle, SystemColors.GrayText, base.BackColor, TextFormatFlags.TextBoxControl | TextFormatFlags.VerticalCenter);
                            }
                        }
                        finally
                        {
                            ReleaseDC(this.Handle, hDC);
                        }
                    }
                }
                else
                {
                    base.WndProc(ref m);
                }
            }
        }
    Gruß Elmar
    Samstag, 12. Januar 2013 16:30
    Beantworter

Alle Antworten