2

I use C#, VisualStudio 2010 and I created a custom UserControl for a Windows Forms application. They don't have much behavior apart from displaying themselves and allowing themselves to be dragged elsewhere. However they are circular in shape and I cannot display them correctly when they overlap on the corners.

Here is my code for painting them on the screen:

  public void Circle_Paint(object sender, PaintEventArgs e)
  {
     var g = e.Graphics;

     g.FillEllipse(brushForOuterCircle, 0, 0, Width, Height);
     g.FillEllipse(brushForInnerCircle, lineWidth, lineWidth, Width - 2*lineWidth, Height - 2*lineWidth);

     if(!textLocation.HasValue)
     {
        SizeF m = g.MeasureString(text, textFont);
        textLocation = new PointF((float)((Width - m.Width)/2.0), (float)((Height - m.Height)/2.0));
     }
     g.DrawString(text, textFont, brushForText, textLocation.Value);
  }

Here is an example of incorrect display, the southeast part of the AB circle does not display because CD overrides that area.

enter image description here How should I prevent that, is there a way to tell the UserControl "you are transparent by default; any portion I don't draw onto should remain so" ?

John Laffoon
  • 2,885
  • 2
  • 26
  • 38
Ali Ferhat
  • 2,511
  • 17
  • 24
  • possible duplicate: [Transparent User Control in .net](http://stackoverflow.com/questions/4117356/transparent-user-control-in-net) and surely many, many others – Cody Gray - on strike Jan 31 '12 at 21:04
  • 1
    I'm aware of that question, however in the accepted answer it says: "One notable thing that doesn't work is overlapping controls. You only see the Parent pixels, not the pixels of the overlapped control. That's fixable but the code is fugly." so if I don't misunderstand it, it doesn't answer my question. does it? – Ali Ferhat Jan 31 '12 at 21:06

3 Answers3

3

Try to:

setup on your user control first WS_EX_COMPOSITED extended style, by overriding

protected override CreateParams CreateParams
{
   get
   {
     CreateParams cp = base.CreateParams;
     cp.ExStyle |= 0x00000020; // add this
     return cp;
   }
}

after do not paint anything in background by

protected override void OnPaintBackground(PaintEventArgs e)
{
   // leave this empty 
}

and finally in Paint draw your shape.

Should work.

Tigran
  • 61,654
  • 8
  • 86
  • 123
1

Try this. Create a TransparencyControl as suggested here: Transparent images with C# WinForms

using System;
using System.Windows.Forms;
using System.Drawing;

public class TransparentControl : Control
{
    private readonly Timer refresher;
    private Image _image;

    public TransparentControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        BackColor = Color.Transparent;
        refresher = new Timer();
        refresher.Tick += TimerOnTick;
        refresher.Interval = 50;
        refresher.Enabled = true;
        refresher.Start();
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x20;
            return cp;
        }
    }

    protected override void OnMove(EventArgs e)
    {
        RecreateHandle();
    }


    protected override void OnPaint(PaintEventArgs e)
    {
        if (_image != null)
        {
            e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
       //Do not paint background
    }

    //Hack
    public void Redraw()
    {
        RecreateHandle();
    }

    private void TimerOnTick(object source, EventArgs e)
    {
        RecreateHandle();
        refresher.Stop();
    }

    public Image Image
    {
        get
        {
            return _image;
        }
        set
        {
            _image = value;
            RecreateHandle();
        }
    }
}
Community
  • 1
  • 1
corylulu
  • 3,449
  • 1
  • 19
  • 35
  • Thanks. Both answers were essentially the same but I accepted the other answer as being the simpler one. (I didn't need periodic refreshes) – Ali Ferhat Feb 01 '12 at 10:22
1

You should also set the region so that it ignores mouse clicks for the area that is supposed to be transparent. Take a look at the following control as an example. It's a control that paints a circle. I set the Region to an Ellipse causing WinForms to not paint the area outside of the circle. By setting the region it also knows to ignore mouse clicks on the area outside of the region.


using System;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public class RoundControl : Control
    {
        private readonly GraphicsPath _path;

        public RoundControl()
        {
            _path = new GraphicsPath();
        }

        protected override void OnResize(EventArgs e)
        {
            _path.Reset();
            _path.AddEllipse(ClientRectangle);
            Invalidate(Region);
            Region = new Region(_path);
            base.OnResize(e);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _path.Dispose();
            }
            base.Dispose(disposing);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            using (Pen borderPen = new Pen(ForeColor, 8))
            {
                e.Graphics.DrawEllipse(borderPen, ClientRectangle);
            }
            base.OnPaint(e);
        }
    }
}

This is what two 'RoundControl' instances look like when rendered in a Form

Community
  • 1
  • 1
Hasani Blackwell
  • 2,026
  • 1
  • 13
  • 10
  • Wonderful, thank you. (Would you consider removing the irrelevant parts, `ResetBorderPen()`, `OnFontChanged()`, `OnForeColorChanged()`so that the answer will be clearer?) – Ali Ferhat Feb 01 '12 at 17:35