如何创建带圆角的用户控件?

时间:2015-10-07 08:44:11

标签: c# .net winforms custom-controls gdi+

我正在尝试使用具有圆角的用户控件。它没有固定的大小,但通常宽度不超过120像素。

我需要用户控件及其内容(标签和表格)有圆角边缘,看起来像圆框。

我已使用此代码。

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

这给控件圆角但是在它运行了几次之后我已经将多个用户控件添加到表单中它将导致泄漏,我将在我的用户控件上获得带有红叉的白盒。 / p>

有更好的方法吗?

3 个答案:

答案 0 :(得分:10)

如果你想要真正的圆角而且不仅仅是透明技巧,你可以使用这个例子:

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

截图将是:

enter image description here

这种方法与透明之间的区别:

  • 设置圆形区域,控件有圆角,你可以看到圆形部分后面的内容,尽管它是透明的,你会看到形状的背景。
  • 设置圆形区域,当您单击删除的圆角部分时,单击穿过该区域并到达后面,但如果使用透明技巧,则单击透明区域将由控件处理。

您可以使用以下两个选项中的任何一个。根据您的要求制作透明或设置区域。

下载

您可以在此处下载代码或克隆存储库:

答案 1 :(得分:1)

仅当您想要“点击”透明区域时,才设置Region。如果圆角不是很大而你只想使角落在视觉上透明,你可以像Button那样做。

这个解决方案的优点是你可以在这里有一个很好的消除锯齿的圆角,而一个区域的边缘总是很清晰。没有提到Region实例持有非托管资源,应该以某种方式处置。

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

答案 2 :(得分:0)

我已经回答了我自己的问题。

根据Sinatr的评论,我发现我无法使用OnHandleCreated,因为我需要在我知道它的大小之前绘制对象。在链接后,Sinatr提供了GetRoundedRegion exception

所以我所做的是将一个IntPtr变量添加到我的UserControl中,该变量在CreateRoundRectRgn方法中使用句柄绘制。在此触发之前,我使用DeleteObject删除旧句柄。

不是最佳解决方案,但目前似乎工作正常。

其他建议虽然好,但在我的情况下无效。