Ali Ferhat
Ali Ferhat

Reputation: 2579

How Can I Display Overlapping User Controls Correctly?

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" ?

Upvotes: 2

Views: 2514

Answers (3)

Hasani Blackwell
Hasani Blackwell

Reputation: 2056

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

Upvotes: 1

Tigran
Tigran

Reputation: 62246

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.

Upvotes: 3

corylulu
corylulu

Reputation: 3499

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();
        }
    }
}

Upvotes: 1

Related Questions