Search code examples
c#winformssystem.drawing

Circular border around another image is not drawing in winforms


I have a picture box control which I have made circular and now I am trying to draw a red circle around it using this:

 Graphics gf = pictureBoxLastLogin1.CreateGraphics();
 gf.DrawEllipse(new Pen(Color.Red, 2), new Rectangle(0, 0, pictureBoxLastLogin1.Width+12, pictureBoxLastLogin1.Height+12));

But it is not drawing anything around the image? What i am doing wrong? Remember i have converted square image to circular image using this code snippet.

System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
gp.AddEllipse(0, 0, pictureBoxLastLogin.Width , pictureBoxLastLogin.Height);
Region rg = new Region(gp);
pictureBoxLastLogin.Region = rg;

Solution

  • When we draw on a Control and we want the drawing to persist, we need to subscribe to the Paint() event of that Control. Or, if it's a Custom Control (a custom class derived from an existing object), to override it's OnPaint() method.

    A Control DC is redrawn quite often. When another Window moves over it, when its Form container is Minimized/Maximized or resized, if this touches a Control visible area an so on.

    When a redrawing is required, the Paint() event is raised.
    A drawing will be preserved only if it is coded inside the Paint() event handler (or the OnPaint() method).
    It's also importat to notice that most of the object used implement IDisposable().
    They all need to be Disposed(). Here, the GraphicsPath object and the drawing Pen.
    The Region applied to the PicturBox should also be disposed. It could be declared at class scope and disposed when the Form closes.

    An example, using (more or less) the same settings used in the question.


    A Form containing a PictureBox and 2 Buttons:
    When Button1 is clicked, it will create a elliptic Region for the PictureBox.
    Button2 will Invalidate() the PictureBox, causing a re-paint to be to scheduled. The Paint() event will be raised.

    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    bool PaintBorder = false;
    int RegionInSet = 8;
    
    private void button1_Click(object sender, EventArgs e)
    {
        using (GraphicsPath path = new GraphicsPath())
        {
            path.AddEllipse(RegionInSet, RegionInSet, pictureBox1.Width - (RegionInSet * 2), 
                            pictureBox1.Height - (RegionInSet * 2));
            Region region = new Region(path);
            pictureBox1.Region = region;
        }
    }
    
    private void button2_Click(object sender, EventArgs e)
    {
        PaintBorder = true;
        pictureBox1.Invalidate();
    }
    
    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (!PaintBorder) return;
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.CompositingMode = CompositingMode.SourceOver;
        e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
    
        using (Pen penRed = new Pen(Color.Red, 12))
        {
            int PenRedOffset = (int)(penRed.Width / 2) + (penRed.Width % 2 == 0 ? -1 : 0);
            e.Graphics.DrawEllipse(penRed,
                new RectangleF(RegionInSet + PenRedOffset, RegionInSet + PenRedOffset,
                               pictureBox1.Width - (PenRedOffset * 2) - (RegionInSet * 2),
                               pictureBox1.Height - (PenRedOffset * 2) - (RegionInSet * 2)));
        }
    }
    

    Visual result:

    enter image description here