Unexpected behavior while rendering Custom Controls(Form) C#

0

Introduction

I am developing custom controls [Here: Form] with custom 3D shape and PathGradient colors. everything is working very smoothly and even I had achieved what I exactly want

Click To View The Actual Image Shape And Color Of The Form

And the whole code to generate this form is given below :-

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.ComponentModel;

namespace CustomControls
{
    public class SplashFORM : Form
    {
        [Description("If True then user can close the form by pressing Alt + F4 while it is focused.")]
        public bool CanClose { get; set; } = false;
        private readonly Timer Drawer = new Timer();

        public SplashFORM()
        {
            FormBorderStyle = FormBorderStyle.None;
            StartPosition = FormStartPosition.CenterScreen;
        }

        protected override void OnFormClosing(FormClosingEventArgs FCEArgs)
        {
            if (!CanClose) { FCEArgs.Cancel = true; return; }
            base.OnFormClosing(FCEArgs);
        }
        
        protected override void OnResize(EventArgs e)
        {
            Invalidate();
            base.OnResize(e);
        }

        protected override void OnLoad(EventArgs EArgs)
        {
            if (!DesignMode)
            {
                DrawForm(null, null);
            }

            base.OnLoad(EArgs);
        }

        private void DrawForm(object _, EventArgs __)
        {
            using (Bitmap BackIMG = new Bitmap(Width, Height))
            {
                using (Graphics Gfx = Graphics.FromImage(BackIMG))
                {
                    Gfx.SmoothingMode = SmoothingMode.HighQuality;
                    FillRoundedRectangle(Gfx);

                    foreach (Control C in Controls)
                    {
                        using (Bitmap BitMP = new Bitmap(C.Width, C.Height))
                        {
                            Rectangle Rect = new Rectangle(0, 0, C.Width, C.Height);
                            C.DrawToBitmap(BitMP, Rect);
                            Gfx.DrawImage(BitMP, C.Location);
                        }
                    }

                    SetBitmap(BackIMG, Left, Top, Handle);
                }
            }
        }

        protected override void OnPaint(PaintEventArgs PEArgs)
        {
            if (DesignMode)
            {
                Graphics Gfx = PEArgs.Graphics;
                Gfx.SmoothingMode = SmoothingMode.HighQuality;
                FillRoundedRectangle(Gfx);
            }

            base.OnPaint(PEArgs);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams Params = base.CreateParams;
                Params.ClassStyle = 0x00020000;
                Params.Style |= 0x00020000;
                if (!DesignMode) { Params.ExStyle |= 0x00080000; }
                return Params;
            }
        }

        protected override void OnPaintBackground(PaintEventArgs PEArgs)
        {
            using (Brush GPBrush = Helper.Get_SplashBrush(new Rectangle(0, 0, Width - 1, Height - 1)))
            { PEArgs.Graphics.FillRectangle(GPBrush, ClientRectangle); }
        }

        private void SetBitmap(Bitmap BitMP, int CLeft, int CTop, IntPtr CHndl)
        {
            if (BitMP.PixelFormat != PixelFormat.Format32bppArgb) throw new ApplicationException("The BitMP must be 32ppp with alpha-channel.");
            IntPtr ScrnDC = Win32.GetDC(IntPtr.Zero);
            IntPtr MemDC = Win32.CreateCompatibleDC(ScrnDC);
            IntPtr HBitMP = IntPtr.Zero;
            IntPtr OBitMP = IntPtr.Zero;
            byte OPCity = 255;

            try
            {
                HBitMP = BitMP.GetHbitmap(Color.FromArgb(0));
                OBitMP = Win32.SelectObject(MemDC, HBitMP);
                Win32.Size _Size = new Win32.Size(BitMP.Width, BitMP.Height);
                Win32.Point _PointSource = new Win32.Point(0, 0);
                Win32.Point _TopPos = new Win32.Point(CLeft, CTop);

                Win32.BLENDFUNCTION _Blend = new Win32.BLENDFUNCTION
                {
                    BlendOp = Win32.AC_SRC_OVER,
                    BlendFlags = 0,
                    SourceConstantAlpha = OPCity,
                    AlphaFormat = Win32.AC_SRC_ALPHA
                };

                Win32.UpdateLayeredWindow(CHndl, ScrnDC, ref _TopPos, ref _Size, MemDC, ref _PointSource, 0, ref _Blend, Win32.ULW_ALPHA);
            }
            finally
            {
                Win32.ReleaseDC(IntPtr.Zero, ScrnDC);

                if (HBitMP != IntPtr.Zero)
                {
                    Win32.SelectObject(MemDC, OBitMP);
                    Win32.DeleteObject(HBitMP);
                }

                Win32.DeleteDC(MemDC);
            }
        }

        private GraphicsPath RoundedRect()
        {
            Rectangle _2DSize = new Rectangle(0, 0, Width - 1, Height - 1);
            int Diameter = 50 * 2;
            Size _Size = new Size(Diameter, Diameter);
            Rectangle _Arc = new Rectangle(_2DSize.Location, _Size);
            GraphicsPath _Path = new GraphicsPath();

            _Path.AddArc(_Arc, 180, 90);
            _Arc.X = _2DSize.Right - 50;
            _Path.AddArc(_Arc, 270, 90);
            _Arc.Y = _2DSize.Bottom - 5;
            _Path.AddArc(_Arc, 0, 90);
            _Arc.X = _2DSize.Left - Diameter;
            _Path.AddArc(_Arc, 90, 90);
            _Path.CloseFigure();
            return _Path;
        }

        private void FillRoundedRectangle(Graphics Gfx)
        {
            if (Gfx == null) throw new ArgumentNullException("Graphics supplied is null");
            using (GraphicsPath GPth = RoundedRect())
            {
                var Bnds = new Rectangle(0, 0, Width - 1, Height - 1);
                PointF[] PT = new PointF[]
            {
                new PointF(-50, -50),
                new PointF(Bnds.Right, 0),
                new PointF(Bnds.Right, Bnds.Bottom),
                new PointF(40, Bnds.Bottom),
                new PointF((float)((float)Bnds.Right / 2 - ((float)Bnds.Bottom * 0.15)), (float)((float)Bnds.Bottom / 2 + ((float)Bnds.Bottom * 0.35)))
            };
                Brush GPBrush = Helper.Get_SplashBrush(Bnds);
                //
                Gfx.FillPath(GPBrush, GPth);
                Region = new Region(GPth);
                //using (Brush GPBrush = Helper.Get_SplashBrush(new Rectangle(0, 0, Width - 1, Height - 1)))
                //{ Gfx.FillPath(GPBrush, GPth); }
            }
        }
    }

    internal class Win32
    {
        public const Int32 ULW_COLORKEY = 0x00000001;
        public const Int32 ULW_ALPHA = 0x00000002;
        public const Int32 ULW_OPAQUE = 0x00000004;
        public const byte AC_SRC_OVER = 0x00;
        public const byte AC_SRC_ALPHA = 0x01;

        [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
        public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);

        [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
        public static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("user32.dll", ExactSpelling = true)]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        public static extern Bool DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll", ExactSpelling = true)]
        public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

        [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        public static extern Bool DeleteObject(IntPtr hObject);

        public enum Bool
        {
            False = 0,
            True
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct Point
        {
            public Int32 x;
            public Int32 y;

            public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct Size
        {
            public Int32 cx;
            public Int32 cy;

            public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct BLENDFUNCTION
        {
            public byte BlendOp;
            public byte BlendFlags;
            public byte SourceConstantAlpha;
            public byte AlphaFormat;
        }
    }

    internal class Helper
    {
        public static Brush Get_SplashBrush(Rectangle Bnds)
        {
            PointF[] PTsGH;
            Color[] CLRsGH;
            PathGradientBrush PGB;

            PTsGH = new PointF[]
            {
                new PointF(-50, -50),
                new PointF(Bnds.Right, 0),
                new PointF(Bnds.Right, Bnds.Bottom),
                new PointF(40, Bnds.Bottom),
                new PointF((float)((float)Bnds.Right / 2 - ((float)Bnds.Bottom * 0.15)), (float)((float)Bnds.Bottom / 2 + ((float)Bnds.Bottom * 0.35)))
            };

            CLRsGH = new Color[]
            {
                Color.FromArgb(120,40,40),
                Color.FromArgb(60, 100, 40),
                Color.FromArgb(50, 50, 120),
                Color.FromArgb(0, 60, 100),
                Color.FromArgb(240, 120, 20, 40)
            };

            PGB = new PathGradientBrush(PTsGH)
            {
                SurroundColors = CLRsGH,
                CenterColor = Color.FromArgb(160, 124, 20)
            };

            return PGB;
        }

        public enum BrushType
        {
            Linear, Path, Solid
        }

        public enum ShapeType
        {
            Rectangular, Circular, Triangular, SplashSpecial
        }
    }
}

The Problem

Everything is very fine till now but when I try to change the opacity of the form by using this code

protected override void OnClick(EventArgs e)
{
    Opacity -= 0.05;
    base.OnClick(e);
}

then the form becomes opaque and looks very dirty

Click To View The Image Of Ugly Form.

I want to change the opacity of the form using a timer to show a fade in and fade out effect!

I tried to use Invalidate(), Update() and Refresh() on the form after changing the opacity but still no luck :(

Is there a way to solve this issue, or is there any alternative to what I want to achieve?

c#
winforms
custom-controls
asked on Stack Overflow Feb 22, 2021 by Techzy Programmer • edited Feb 22, 2021 by James Z

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0