How to create a custom control with rounded corners?

I am trying to have a user control that has rounded corners. It does not have a fixed size, but usually it does not have a width much larger than 120 pixels.

I need the User Control and its contents (shortcut and table) to have rounded edges and look like a round rectangle.

I used this code.

[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] private static extern IntPtr CreateRoundRectRgn ( int nLeftRect, // x-coordinate of upper-left corner int nTopRect, // y-coordinate of upper-left corner int nRightRect, // x-coordinate of lower-right corner int nBottomRect, // y-coordinate of lower-right corner int nWidthEllipse, // height of ellipse int nHeightEllipse // width of ellipse ); public static System.Drawing.Region GetRoundedRegion(int controlWidth, int controlHeight) { return System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, controlWidth - 5, controlHeight - 5, 20, 20)); } 

This gives control to rounded corners, but after it works several times, and I added a few elements of my user control to the form, which will cause a leak, and I get a white box with a red cross on my user controls.

Is there a better way to do this?

+7
source share
3 answers

If you want a really round corner, not just a transparent trick, you can use this example:

 private int radius=20; [DefaultValue(20)] public int Radius { get { return radius; } set { radius = value; this.RecreateRegion(); } } private GraphicsPath GetRoundRectagle(Rectangle bounds, int radius) { GraphicsPath path = new GraphicsPath(); path.AddArc(bounds.X, bounds.Y, radius, radius, 180, 90); path.AddArc(bounds.X + bounds.Width - radius, bounds.Y, radius, radius, 270, 90); path.AddArc(bounds.X + bounds.Width - radius, bounds.Y + bounds.Height - radius, radius, radius, 0, 90); path.AddArc(bounds.X, bounds.Y + bounds.Height - radius, radius, radius, 90, 90); path.CloseAllFigures(); return path; } private void RecreateRegion() { var bounds = ClientRectangle; bounds.Width--; bounds.Height--; using (var path = GetRoundRectagle(bounds, this.Radius)) this.Region = new Region(path); this.Invalidate(); } protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); this.RecreateRegion(); } 

And the screenshot will be:

enter image description here

The difference between this approach and transparency:

  • By setting a circular area, the control has really round corners, and you can see what is behind the circular part, despite the fact that when it is transparent, you will see the background of the form.
  • When setting up a rounded area, when you click on the removed rounded part, click the area pass and drag to the back, but if you use the transparency trick, clicking on the transparent area will be processed by the control.

You can use any of these 2 options. Create a transparent or customize region based on your requirements.

Download

You can download the code or clone the repository here:

+10
source

Setting Region makes sense only if you want to β€œclick” a transparent area. If the rounded corners are not so large, and you just want to make the corners visually transparent, you can do the same thing as Button .

The advantage of this solution is that here you can have a beautiful, smooth corner angle, while the edges of the area are always sharp. Not to mention that the Region instance contains unmanaged resources and must be somehow removed.

 protected override void OnPaint(PaintEventArgs e) { PaintTransparentBackground(this, e); // TODO: Paint your actual content here with rounded corners } private static void PaintTransparentBackground(Control c, PaintEventArgs e) { if (c.Parent == null || !Application.RenderWithVisualStyles) return; ButtonRenderer.DrawParentBackground(e.Graphics, c.ClientRectangle, c); } 
+1
source

I answered my question.

After commenting on Sinatr, I found that I could not use OnHandleCreated, since I needed to draw an object before I knew what its size was. Sinatr link provides GetRoundedRegion exception

So what I did, an IntPtr variable was added to my UserControl, which is assigned to the CreateRoundRectRgn method with each paint using a handle. Before this trigger, I use DeleteObject to delete the old handle.

Not an optimal solution, but so far it is working fine.

Other suggestions, while good ones, will not work in my case.

0
source

All Articles