开发者

Drop shadow in Winforms Controls?

is there a way to add a drop shadow to controls?

are there a开发者_JAVA技巧ny controls out there with this feature?


You have to overwrite the CreateParamsproperty like this:

private const int CS_DROPSHADOW = 0x00020000;
protected override CreateParams CreateParams
{
    get
    {
        // add the drop shadow flag for automatically drawing
        // a drop shadow around the form
        CreateParams cp = base.CreateParams;
        cp.ClassStyle |= CS_DROPSHADOW;
        return cp;
    }
}


This question has been around for 6 years and needs an answer. I hope that anyone who needs to do this can extrapolate an answer for any control set from my solution. I had a panel and wanted to draw a drop shadow underneath every child control - in this instance one or more panels (but the solution should hold good for other control types with some minor code changes).

As the drop shadow for a control has to be drawn on the surface of that control's container we start by adding a function to the container's Paint() event.

Container.Paint += dropShadow;

dropShadow() looks like this:

    private void dropShadow(object sender, PaintEventArgs e)
    {
        Panel panel = (Panel)sender;
        Color[] shadow = new Color[3];
        shadow[0] = Color.FromArgb(181, 181, 181);
        shadow[1] = Color.FromArgb(195, 195, 195);
        shadow[2] = Color.FromArgb(211, 211, 211);
        Pen pen = new Pen(shadow[0]);
        using (pen)
        {
            foreach (Panel p in panel.Controls.OfType<Panel>())
            {
                Point pt = p.Location;
                pt.Y += p.Height;
                for (var sp = 0; sp < 3; sp++)
                {
                    pen.Color = shadow[sp];
                    e.Graphics.DrawLine(pen, pt.X, pt.Y, pt.X + p.Width - 1, pt.Y);
                    pt.Y++;
                }
            }
        }
    }

Clearly you can pick a different control type from the container's collection and you can vary the colour and depth of the shadow with some minor tweaks.


The top answer does in fact generate a shadow, but I personally wasn't satisfied with it for a few reasons:

  • It only works for rectangles (granted, WinForms controls are all rectangles, but we might want to use this in other cases)
  • More importantly: It's not smooth. It doesn't look as natural as other shadows in other programs look.
  • Finally, it's slightly annoying to configure.

So, because of all these things, I ended up writing my own for my project and I thought I'd share it here:

public partial class Form1 : Form
{
    List<Control> shadowControls = new List<Control>();
    Bitmap shadowBmp = null;
    public Form1()
    {
        InitializeComponent();
        shadowControls.Add(panel1);
        this.Refresh();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        if (shadowBmp == null || shadowBmp.Size != this.Size)
        {
            shadowBmp?.Dispose();
            shadowBmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
        }
        foreach (Control control in shadowControls)
        {
            using (GraphicsPath gp = new GraphicsPath())
            {
                gp.AddRectangle(new Rectangle(control.Location.X, control.Location.Y, control.Size.Width, control.Size.Height));
                DrawShadowSmooth(gp, 100, 60, shadowBmp);
            }
            e.Graphics.DrawImage(shadowBmp, new Point(0, 0));
        }
    }
    private static void DrawShadowSmooth(GraphicsPath gp, int intensity, int radius, Bitmap dest)
    {
        using (Graphics g = Graphics.FromImage(dest))
        {
            g.Clear(Color.Transparent);
            g.CompositingMode = CompositingMode.SourceCopy;
            double alpha = 0;
            double astep = 0;
            double astepstep = (double)intensity / radius / (radius / 2D);
            for (int thickness = radius; thickness > 0; thickness--)
            {
                using (Pen p = new Pen(Color.FromArgb((int)alpha, 0, 0, 0), thickness))
                {
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, gp);
                }
                alpha += astep;
                astep += astepstep;
            }
        }
    }
}

In this implementation, all Controls added to the shadowControls will be painted with a smooth shadow. You should be able to implement this for non-rectangular shapes because the main function to generate the shadows takes a GraphicsPath. Please note that it's important you draw the shadow to another bitmap before drawing it to the form because the main function requires a compositing mode of SourceCopy to work, which means if you don't draw it to another surface first anything behind the shadow will be completely replaced and the transparency aspect is useless. I'm on a roll of answering 10-year-old questions, but hopefully, this helps someone!


There is in WPF if you can stretch to using that instead, I don't believe there is an alternative in Windows Forms due to the limited capabilities of GDI+.


Here's a controversial opinion, you do it without code. Set your main panel Border Style to Fixed Single. Create 3 panels below it, each 1 pixel larger in every direction. Each of the 3 panels is of a lighter shade of gray. Not perfect but cheap and easy.

panel with pseudo-shadow

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜