Comment créer un contrôle utilisateur avec des coins arrondis?

J’essaie d’avoir un contrôle utilisateur qui a des coins arrondis. Il n’a pas de taille fixe, mais sa largeur ne dépasse généralement pas 120 pixels.

J’ai besoin que le contrôle utilisateur et son contenu (une étiquette et un tableau) aient des bords arrondis et ressemblent à une boîte ronde.

J’ai utilisé ce 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)); } 

Cela donne au contrôle des angles arrondis, mais après quelques instants de fonctionnement et l’ajout de multiples de mon contrôle d’utilisateur au formulaire, une fuite s’ensuivra et j’obtiendrai la whitebox avec une croix rouge sur mes contrôles d’utilisateur.

Existe-t-il une meilleure façon de le faire?

Si vous voulez vraiment un coin arrondi et pas seulement un truc transparent, vous pouvez utiliser cet exemple:

 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 = new Rectangle(this.ClientRectangle.Location, this.ClientRectangle.Size); bounds.Inflate(-1, -1); 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(); } 

Et la capture d’écran sera:

entrez la description de l'image ici

La différence entre cette approche et la transparence:

  • Si vous définissez une zone arrondie, le contrôle présente des angles très arrondis et vous pouvez voir ce qui se cache derrière la partie arrondie, même si elle est transparente, vous verrez le fond de la forme.
  • En définissant une région arrondie, lorsque vous cliquez sur une partie arrondie supprimée, cliquez sur passer à travers la région et va au-delà, mais si vous utilisez une astuce de transparence, cliquez sur la région transparente gérée par le contrôle.

Vous pouvez utiliser l’une de ces 2 options. Rendre transparente ou définir la région en fonction de vos besoins

Télécharger

Vous pouvez télécharger le code ou cloner le référentiel ici:

  • r-aghaei / RoundCornerControlExample

La définition de la Region n’a de sens que si vous souhaitez “cliquer sur” la zone transparente. Si les angles arrondis ne sont pas aussi grands et que vous souhaitez simplement rendre les angles transparents, vous pouvez procéder de la même manière que Button .

L’avantage de cette solution est que vous pouvez avoir ici un beau coin arrondi anti-aliasé, alors que les bords d’une région sont toujours nets. Sans mentionner qu’une instance de Region contient des ressources non gérées et devrait être éliminée d’une manière ou d’une autre.

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

J’ai répondu à ma propre question.

Après le commentaire de Sinatr, j’ai constaté que je ne pouvais pas utiliser OnHandleCreated, car je devais être sur le sharepoint peindre l’object avant de savoir quelle serait sa taille. En suivant le lien, Sinatr a fourni une exception GetRoundedRegion

Donc, ce que j’ai fait est ajouté une variable IntPtr à mon UserControl qui est atsortingbué à la méthode CreateRoundRectRgn chaque peinture avec le handle. Avant que cela ne se déclenche, j’utilise DeleteObject pour supprimer l’ancien descripteur.

Pas une solution optimale mais semble fonctionner correctement pour le moment.

Les autres suggestions, bien que bonnes, ne fonctionneraient pas dans mon cas.