2015-10-07 15 views
5

Ich versuche, ein Benutzersteuerelement mit abgerundeten Ecken zu haben. Es hat keine feste Größe, aber es hat normalerweise keine Breite viel mehr als 120 Pixel.So erstellen Sie ein Benutzersteuerelement mit abgerundeten Ecken?

Ich brauche das User Control und seinen Inhalt (ein Label und eine Tabelle), um abgerundete Kanten zu haben und wie eine runde Box aussehen.

Ich habe diesen Code verwendet.

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

Dies gibt die Steuer abgerundete Ecken, aber nachdem es afew mal ausgeführt worden, und ich habe ein Vielfach von meinen User Control zu dem Formular hinzugefügt wird es ein Leck verursachen, und ich werde die Whitebox mit einem roten Kreuz bekommt auf meinem Benutzersteuerelemente.

Gibt es einen besseren Weg, dies zu tun?

+1

Ich hatte dieses Problem auch. Und glauben Sie mir, lassen Sie WinForms los und beginnen Sie mit 'WPF'. Viel besser für das Customizing! – kevintjuh93

+0

Wie benutzt man 'CreateRoundRectRgn'? Ähnlich wie [das] (http://stackoverflow.com/q/17787573/1997232)? Dann haben Sie natürlich einen Griff Leck. Möchten Sie den Fehler beheben (dann Postleitzahl wo Sie ihn verwenden) oder nach Alternativen suchen? Eine Alternative könnte ein [transparent] (http://stackoverflow.com/q/9358500/1997232) Steuerelement mit Bildern mit abgerundeten Ecken sein. – Sinatr

+0

Sinatr, Sie haben Recht Dies ist genau, wie ich dies tue, GetRoundedRegion wird aufgerufen, wenn das Formular neu gezeichnet wird, leider kann ich diese Methode in der OnHandleCreated() wie in Ihrem Link vorgeschlagen, da die Größe sehr variabel ist Bei der Erstellung von Handle ist die Controls-Größe die Standardgröße und es geht abit random. – CJM

Antwort

1

Die Einstellung Region ist nur sinnvoll, wenn Sie den transparenten Bereich "durchklicken" möchten. Wenn die abgerundeten Ecken nicht so groß sind und Sie möchten nur die Ecken optisch transparent machen, können Sie das gleiche tun wie Button tut.

Der Vorteil dieser Lösung, dass Sie eine schöne Anti-Aliased abgerundete Ecke hier haben können, während die Kanten einer Region immer scharf sind. Nicht zu erwähnen, dass eine Region Instanz verwaltet nicht verwaltete Ressourcen und sollte irgendwie entsorgt werden.

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

Leider, wenn ich versuche, die Paint-Methode zu übersteuern, wird es nur nicht auf meiner Benutzersteuerung ausgelöst. – CJM

+0

Ich habe das Beispiel korrigiert, im Gegensatz zum 'Paint'-Ereignis hat die' OnPaint'-Methode kein 'sender'-Argument. – taffer

8

Wenn Sie wirklich runde Ecke wollen und nicht nur transparent Trick können Sie dieses Beispiel verwenden:

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); 
    this.Region = new Region(GetRoundRectagle(bounds, this.Radius)); 
    this.Invalidate(); 
} 
protected override void OnSizeChanged(EventArgs e) 
{ 
    base.OnSizeChanged(e); 
    this.RecreateRegion(); 
} 

Und Screenshot wird:

enter image description here

Der Unterschied zwischen diesem Ansatz und transparent machen:

  • Einstellung runden Bereich, das Steuerelement hat wirklich runde Ecken und Sie können sehen, was hinter dem runden Teil ist, obwohl wenn es transparent ist, werden Sie Hintergrund der Form sehen.
  • Einstellung runden Bereich, wenn Sie auf abgerundete Teil klicken, klicken Sie durch die Region und reicht nach hinten, aber wenn Sie Transparenz Trick verwenden klicken Sie auf transparente Region wird durch das Steuerelement behandelt.

Sie können eine dieser 2 Optionen verwenden. Transparent machen oder Region basierend auf Ihrer Anforderung einstellen.

+0

Wie würden Sie einen Rahmen hinzufügen? Ich brauche etwas, das wie der FixedSingle BorderStyle ist, und habe dies auf dem Steuerelement festgelegt, aber wenn der obige Code ausgeführt wird, scheint er entfernt zu werden. – Sam07

+0

@Sam 'GetRoundRectagle' gibt einen Pfad zurück, mit dem Sie den Pfad in' e.Graphics.DrawPath() 'verwenden können, um einen Rahmen um den Pfad zu zeichnen. Lesen Sie die letzten beiden Noten der Antwort sorgfältig durch. (Für glattere Kanten haben Sie die Möglichkeit, die Region unverändert zu lassen und die Kontrolle nur durch eine transparente Hintergrundfarbe zu unterstützen. Der Unterschied besteht nur darin, dass einige Steuerelemente überlappen. Um zu verstehen, was ich meine, werfen Sie einen Blick auf [diesen Beitrag] (http://stackoverflow.com/questions/35467199/is-this-possible-to-have-triangular-picturebox-inde-the-rectangular-one), können Sie es nützlich finden). –

0

Ich habe meine eigene Frage beantwortet.

Nach Sinatrs Kommentar habe ich festgestellt, dass ich das OnHandleCreated nicht verwenden konnte, da ich das Objekt malen musste, bevor ich wusste, wie groß es wäre. Folgen Sie dem Link Sinatr zur Verfügung gestellt GetRoundedRegion exception

Also was ich getan habe, ist eine IntPtr-Variable zu meinem UserControl hinzugefügt, die auf der CreateRoundRectRgn-Methode jede Farbe mit dem Handle zugeordnet ist. Bevor dies ausgelöst wird, verwende ich das DeleteObject, um das alte Handle zu entfernen.

Keine optimale Lösung, aber scheint für jetzt gut zu funktionieren.

Die anderen Vorschläge zwar gut, würde in meinem Fall nicht funktionieren.

+0

Die Antwort, die ich gepostet habe, funktioniert ordnungsgemäß, Sie können den Screenshot sehen. Und es verwendet GDI + :) –

+0

Ihre Methode funktioniert Reza, aber die Ecken sind nicht identisch und die Seiten meiner Kontrolle schrumpfen etwas. Etwas Fiedeln würde das sicher beheben. Ich werde wahrscheinlich zurückgehen und Ihre Lösung in der Zukunft implementieren, wenn ich etwas Freizeit habe, da ich denke, dass es eine bessere Lösung ist, für jetzt bin ich glücklich mit dem, was ich habe. Prost obwohl :) – CJM

+0

Vielen Dank für Ihren Kommentar. Nicht identische Ecken werden einfach fixiert. –

Verwandte Themen