如何在WindowsForms上绘制自定义控件的边框?

时间:2017-07-20 05:37:53

标签: c# winforms

我尝试使用下面的代码

为我的自定义控件绘制边框
 protected override void WndProc(ref Message msg)
    {
        switch (msg.Msg)
        {
            case NativeMethods.WM_NCPAINT:
            case NativeMethods.WM_SIZE:
                base.WndProc(ref msg);
                this.WmNcPaint(ref msg);
                break;
            default:
                base.WndProc(ref msg);
                break;
        }
    }


    /// <summary></summary>
    /// <param name="msg"/>
    private void WmNcPaint(ref Message msg)
    {
        this.DrawThemedBorderColor(this, ref msg);

    }

    private IntPtr cachedRgn = IntPtr.Zero;

    public void DrawThemedBorderColor(Control control, ref Message msg)
    {
        this.cachedRgn = NCPaintHelper(control, ref msg);
    }


    public IntPtr NCPaintHelper(Control control, ref Message m)
    {
        IntPtr hdc = IntPtr.Zero;
        Graphics g = null;
        IntPtr hwnd = m.HWnd;
        IntPtr remainingClipRegion = IntPtr.Zero;

        try
        {
            Rectangle clipRect;
            Rectangle desktopBounds = GetDesktopBounds(control);
            Rectangle bounds = desktopBounds;
            bounds.X = bounds.Y = 0;

            hdc = NativeMethods.GetWindowDC(m.HWnd);

            if (hdc != IntPtr.Zero)
            {
                if (m.WParam.ToInt64() == 1 || m.WParam == IntPtr.Zero)
                {
                    // Since we will be painting the client rect.
                    clipRect = bounds;
                }
                else
                {
                    Rectangle rect = desktopBounds;
                    Point pt = new Point(rect.Left, rect.Top);
                    NativeMethods.RECT r = new NativeMethods.RECT();

                    NativeMethods.GetRgnBox(m.WParam, ref r);
                    clipRect = new Rectangle(r.left, r.top, r.Width, r.Height);
                    clipRect.Intersect(rect);
                    clipRect.Offset(-pt.X, -pt.Y);
                }

                g = Graphics.FromHdc(hdc);
                g.SetClip(clipRect, System.Drawing.Drawing2D.CombineMode.Replace);
                g.Clip = new Region(clipRect);
                PaintEventArgs pe = new PaintEventArgs(g, clipRect);
                remainingClipRegion = NonClientPaint(pe, bounds, desktopBounds);

                // When wParam is 1, the entire window frame needs to be updated.
                if (m.WParam.ToInt64() == 1 || m.WParam == IntPtr.Zero)
                {
                    // No existing clipping region, just replace it.
                    m.WParam = IntPtr.Add(IntPtr.Zero, 2);// remainingClipRegion;
                }
            }
        }
        finally
        {
            if (g != null)
            {
                g.Dispose();
            }
            if (hdc != IntPtr.Zero)
            {
                NativeMethods.ReleaseDC(hwnd, hdc);
            }
        }

        return IntPtr.Zero;
    }

    IntPtr NonClientPaint( PaintEventArgs e, Rectangle displayRect, Rectangle windowRectInScreen )
    {
        Graphics g = e.Graphics;
        Rectangle bounds = displayRect;
        // Draw border with themed border color.
        // Draw lines, don't fill a rectangle.
        using( Pen pen = new Pen( Color.Red ) )
        {
            g.DrawLine(pen, bounds.Location, new Point(bounds.Right, bounds.Y));
            g.DrawLine(pen, bounds.Location, new Point(bounds.X, bounds.Height));
            g.DrawLine(pen, new Point(bounds.X, bounds.Height - 1), new Point(bounds.Right - 1, bounds.Height - 1));
            g.DrawLine(pen, new Point(bounds.Right - 1, bounds.Y), new Point(bounds.Right - 1, bounds.Height - 1));
        }

        return NativeMethods.CreateRectRgn(0, 0, 0, 0); //windowRectInScreen.Left + 1, windowRectInScreen.Top + 1, windowRectInScreen.Right - 1, windowRectInScreen.Bottom - 1 );
    }


    protected override CreateParams CreateParams
    {
        get
        {
            var cp = base.CreateParams;

            switch (this.borderStyle)
            {
                case BorderStyle.Fixed3D:
                    cp.ExStyle |= 0x200; // WS_EX_DLGFRAME
                    break;
                case BorderStyle.FixedSingle:
                    cp.Style |= 0x800000; // WS_BORDER
                    break;
            }
            return cp;
        }
    }

此代码在除Windows-XP OS之外的所有操作系统中都能正常运行。在XP os中,边界已经部分绘制。请参阅下面附带的屏幕截图和示例链接,

enter image description here

示例链接: https://drive.google.com/open?id=0B6mYuvHmZAe-ay01ZTlvaGxSODA

请告诉我们,我为自定义控件绘制自定义边框时缺少什么。

谢谢,

1 个答案:

答案 0 :(得分:0)

看起来你在绘制边框时遇到了很多麻烦。我不肯定这会对你的Win XP问题有所帮助,但它值得一试。当我想在自定义UserControls

的外边缘绘制边框时,我会这样做
public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
        MyInitializeComponent();
    }

    private void MyInitializeComponent()
    {
        this.Paint += MyUserControl_Paint;
    }

    private void MyUserControl_Paint(object sender, PaintEventArgs e)
    {
        // Draw a border around the outside border of the control
        var pen = new Pen(Color.Black, 2f);
        e.Graphics.DrawRectangle(pen, this.ClientRectangle);
    }
}