10

I'm trying to deal with TextBox text's color under DWM Glass. I read a lot of material, still no perfect solution.

The almost perfect results code i found here: http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/316a178e-252b-480d-8cc9-85814c2073d8/ , but it has a lot of flicking and event-specific operations (For example: type some text and push Home button).

I trying to solve those problems.

The following code is a mutation of the original code, but it does not relies on any event, just WM_PAINT. It still flicking, and the caret (text cursor) is disappeared somehow!

How to prevent flickering, and how to get the caret (text cursor) back?

Thanks.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;

namespace AeroWindowsFormsApplication
{
    public class AeroTextBox : TextBox
    {
        private const int WM_PAINT = 0xf;

        private bool _aeroFix;

        public AeroTextBox()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
        }

        protected override void WndProc(ref Message m)
        {
            if (_aeroFix)
            {
                switch (m.Msg)
                {
                    case WM_PAINT:
                        RedrawAsBitmap();
                        m.Result = new IntPtr(1);
                        break;

                    default:
                        base.WndProc(ref m);
                        break;
                }
            }
            else
            {
                base.WndProc(ref m);
            }
        }

        private void RedrawAsBitmap()
        {
            using (Bitmap bm = new Bitmap(this.Width, this.Height))
            using (Graphics g = this.CreateGraphics())
            {
                this.DrawToBitmap(bm, this.ClientRectangle);
                g.DrawImageUnscaled(bm, -1, -1);
            }
        }

        public bool AeroFix
        {
            get { return _aeroFix; }
            set 
            {
                if (_aeroFix != value)
                {
                    Invalidate();
                }

                _aeroFix = value;
            }
        }
    }
}
DxCK
  • 4,402
  • 7
  • 50
  • 89
  • I started a bounty to generally improve the method. Mostly avoid flicking, avoid invalidations, etc. I don't really mind how ugly the code has to be. – Lazlo Apr 20 '11 at 03:05
  • Another point: I don't know what AeroFix even does in this code, since it's never set. But please refer to the original code in VB (linked in post) which indicated a per-event invalidation code. – Lazlo Apr 20 '11 at 03:09
  • 1
    You could just use WPF, and live happily ever after. – Claus Jørgensen Apr 23 '11 at 00:24
  • Winforms is a constraint in my case – DxCK Apr 23 '11 at 13:32

1 Answers1

1

If you set the TransparencyKey of the form to the background color in the glass area then, you can use any control over it, but you cannot use the color specified in the TransparencyKey in any one of the controls placed there.

This method has an inconvenient of allowing you to click through the glass on the window in the background. But there may be a way around this too.

EDIT: I have been searching for this for a long time now... it must be impossible then. The carret is managed by windows API itself, you cannot force it to appear in the way you want. What you could do is to draw the whole text-box yourself... but that whould be too much work for so little.

I summary: GDI+ and DWM do not combine very well. I give up.

Miguel Angelo
  • 23,796
  • 16
  • 59
  • 82
  • 1
    This method has also another inconvenient of showing the TransparencyKey color instead of glass inside Image with gradual alpha channel. – DxCK Apr 26 '11 at 17:25
  • Agreed with DxCK. And a way around the click-through problem is to set the values to different bytes (200, 200, 201). Without any mean to degrade your answer, I hope this doesn't get awarded the bounty by default. It looks like a "bounty hunter" answer. Edit: Lol, the bounty ended minutes ago. I can choose the person who gets it. – Lazlo Apr 27 '11 at 03:30
  • @Lazlo: a bounty only goes to a person automatically when there is at least 2 up votes. – Miguel Angelo Apr 28 '11 at 15:29