winform中TreeView透明背景

@bruce  September 27, 2019

TreeView本身不支持透明背景,重写WndProc以支持背景图片。

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

namespace MyControl
{
    /// <summary>
    /// Displays a hierarchical collection of labeled items, each represented by a System.Windows.Forms.TreeNode.
    /// </summary>
    [
    //Use the same attibutes as TreeView
    DesignerAttribute("System.Windows.Forms.Design.TreeViewDesigner, System.Design, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
    DefaultPropertyAttribute("Nodes"),
    DefaultEventAttribute("AfterSelect")
    ]
    public class UTreeView : TreeView
    {

        Bitmap internalBitmap = null;
        Graphics internalGraphics = null;
        Image image = null;

        private void DisposeInternal()
        {
            if (internalGraphics != null)
                internalGraphics.Dispose();
            if (internalBitmap != null)
                internalBitmap.Dispose();

        }
        /// <summary>Releases resources.</summary>
        /// <param name="disposing">true = Both managed and unmanaged, false = Unmanaged only.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
                DisposeInternal();
            base.Dispose(disposing);
        }

        /// <summary>Occurs when window is resized.</summary>
        /// <param name="e">A System.EventArgs.Empty.</param>
        /// <remarks>Recreates internal Graphics object. </remarks>
        protected override void OnResize(System.EventArgs e)
        {
            if (internalBitmap == null ||
                internalBitmap.Width != Width || internalBitmap.Height != Height)
            {

                if (Width != 0 && Height != 0)
                {
                    DisposeInternal();
                    internalBitmap = new Bitmap(Width, Height);
                    internalGraphics = Graphics.FromImage(internalBitmap);
                }
            }
        }

        /// <summary>Occurs when a Windows message is dispatched.</summary>
        /// <param name="message">Message to process.</param>
        /// <remarks>Overrides WM_PAINT, WM_ERASEBKGND.</remarks>
        public void setBackGround(Image bk = null)
        {
            if (bk != null)
            {
                image = bk;
            }
            else
            {
                Bitmap bm = new Bitmap(this.Parent.BackgroundImage, this.Parent.Width, this.Parent.Height);
                //绘制矩形,定义你需要截取的图像起始位置和宽高
                Rectangle rs = new Rectangle(this.Location.X, this.Location.Y, this.Width, this.Height);

                //按矩形尺寸和起始位置截取bm的一部分
                bm = bm.Clone(rs, System.Drawing.Imaging.PixelFormat.Undefined);
                image = bm;

            }
        }

        /// <summary>Occurs when a Windows message is dispatched.</summary>
        /// <param name="message">Message to process.</param>
        /// <remarks>Overrides WM_PAINT, WM_ERASEBKGND.</remarks>
        protected override void WndProc(ref Message message)
        {
            const int WM_PAINT = 0x000F;
            const int WM_PRINTCLIENT = 0x0318;
            const int WM_ERASEBKGND = 0x0014;

            switch (message.Msg)
            {

                case WM_ERASEBKGND:
                    return;

                case WM_PAINT:
                    // The designer host does not call OnResize()                    
                    if (internalGraphics == null)
                        OnResize(EventArgs.Empty);

                    //Set up 
                    Win32.RECT updateRect = new Win32.RECT();
                    if (Win32.GetUpdateRect(message.HWnd, ref updateRect, false) == 0)
                        break;

                    //Draw Internal Graphics
                    IntPtr hdc = internalGraphics.GetHdc();
                    Message printClientMessage = Message.Create(Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero);
                    DefWndProc(ref printClientMessage);
                    internalGraphics.ReleaseHdc(hdc);

                    //Add the missing OnPaint() call
                    OnPaint(new PaintEventArgs(internalGraphics, Rectangle.FromLTRB(
                        updateRect.left,
                        updateRect.top,
                        updateRect.right,
                        updateRect.bottom)));


                    Win32.PAINTSTRUCT paintStruct = new Win32.PAINTSTRUCT();
                    //IntPtr screenHdc1 = Win32.BeginPaint(message.HWnd, ref paintStruct);
                    IntPtr screenHdc = Win32.GetDC(message.HWnd);
                    using (Graphics screenGraphics = Graphics.FromHdc(screenHdc))
                    {
                        //Draw Screen Graphics

                        Bitmap temp = new Bitmap(internalBitmap, internalBitmap.Size);
                        temp.MakeTransparent(Color.White);
                        internalGraphics.FillRectangle(Brushes.White, 0, 0, this.Bounds.Width, this.Bounds.Height);
                        if (image != null)
                            internalGraphics.DrawImage(image, 0, 0, image.Width, image.Height);
                        internalGraphics.DrawImage(temp, 0, 0, temp.Width, temp.Height);

                        screenGraphics.DrawImage(internalBitmap, 0, 0);
                    }

                    //Tear down
                    int ret = Win32.ReleaseDC(message.HWnd, screenHdc);
                    Win32.ValidateRect(message.HWnd, ref updateRect);
                    //Win32.EndPaint( message.HWnd, ref paintStruct );
                    return;
            }
            base.WndProc(ref message);
        }

        /// <summary>Occurs when the control is redrawn.</summary>
        /// <remarks>Re enable browsing attributes for the Paint Event.</remarks>
        [
        EditorBrowsableAttribute(EditorBrowsableState.Always),
        BrowsableAttribute(true)
        ]
        public new event PaintEventHandler Paint
        {
            add { base.Paint += value; }
            remove { base.Paint -= value; }
        }
    }

    /// <summary>
    /// Win32 PInvoke declarations
    /// </summary>
    internal class Win32
    {
        [DllImport("User32.dll")]
        public static extern int GetUpdateRect(IntPtr hwnd, ref RECT rect, bool erase);

        [DllImport("User32.dll")]
        public static extern int ValidateRect(IntPtr hwnd, ref RECT rect);

        [DllImport("User32.dll", SetLastError = true)]
        public static extern bool GetWindowRect(IntPtr handle, ref RECT rect);

        [DllImport("User32.dll")]
        public static extern IntPtr BeginPaint(IntPtr hWnd, ref PAINTSTRUCT paintStruct);

        [DllImport("User32.dll")]
        public static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT paintStruct);

        [DllImport("User32.dll")]
        public static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("User32.dll")]
        public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct PAINTSTRUCT
        {
            public IntPtr hdc;
            public int fErase;
            public RECT rcPaint;
            public int fRestore;
            public int fIncUpdate;
            public int Reserved1;
            public int Reserved2;
            public int Reserved3;
            public int Reserved4;
            public int Reserved5;
            public int Reserved6;
            public int Reserved7;
            public int Reserved8;
        }
    }
}

添加新评论