I am trying to create a custom control that resembles a long rectangle with rounded corners and a border. It will also contain some text, an icon and so forth, but I am having issues with the manual drawing of the control when added programmatically to my form.
The code looks like so:
Option Explicit On
Option Strict On
Imports System.Runtime.InteropServices
Imports Transitions
Imports System.Drawing.Drawing2D
Public Class AlertPanel
Private m_Radius As Integer
Private m_BorderWidth As Integer
Private m_AlertType As AlertType
Private m_Icon As Image
''' <summary>
''' Indicates a Radius of the control's corners
''' </summary>
''' <returns>The corner Radius.</returns>
Public Property Radius As Integer
Get
Return m_Radius
End Get
Set(value As Integer)
m_Radius = value
End Set
End Property
''' <summary>
''' Indicates the width to draw the outer border of the control.
''' </summary>
''' <returns>The border width.</returns>
Public Property BorderWidth As Integer
Get
Return m_BorderWidth
End Get
Set(value As Integer)
m_BorderWidth = value
End Set
End Property
''' <summary>
''' Indicates the type of Alert for the control.
''' </summary>
''' <returns>The Alert type.</returns>
Public Property AlertType As AlertType
Get
Return m_AlertType
End Get
Set(value As AlertType)
m_AlertType = value
End Set
End Property
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Private Sub AlertPanel_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim rect As Rectangle = Me.ClientRectangle 'Drawing Rounded Rectangle
rect.X = rect.X + 1
rect.Y = rect.Y + 1
rect.Width -= 2
rect.Height -= 2
Using bb As GraphicsPath = GetPath(rect, Radius)
'Draw the background
Using br As Brush = New SolidBrush(BackColor)
e.Graphics.SmoothingMode = SmoothingMode.HighQuality
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
e.Graphics.FillPath(br, bb)
End Using
'Draw the border
Using br As Brush = New SolidBrush(ForeColor)
rect.Inflate(-1, -1)
e.Graphics.SmoothingMode = SmoothingMode.HighQuality
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
e.Graphics.DrawPath(New Pen(br, BorderWidth), bb)
End Using
End Using
End Sub
Protected Function GetPath(ByVal rc As Rectangle, ByVal r As Int32) As GraphicsPath
Dim x As Int32 = rc.X, y As Int32 = rc.Y, w As Int32 = rc.Width, h As Int32 = rc.Height
r = r << 1
Dim path As GraphicsPath = New GraphicsPath()
If r > 0 Then
If (r > h) Then r = h
If (r > w) Then r = w
path.AddArc(x, y, r, r, 180, 90)
path.AddArc(x + w - r, y, r, r, 270, 90)
path.AddArc(x + w - r, y + h - r, r, r, 0, 90)
path.AddArc(x, y + h - r, r, r, 90, 90)
path.CloseFigure()
Else
path.AddRectangle(rc)
End If
Return path
End Function
End Class
Then I call it like this:
Dim a As New AlertPanel
With a
.Size = New Size(400, 60)
.Location = New Point(100, 200)
.AlertType = AlertType.Major
.ForeColor = Color.Black
.BorderWidth = 1
.BackColor = Color.IndianRed
.Radius = 10
End With
Me.Controls.Add(a)
And I am left with this:
UPDATE
After some edits to my code as per Plutonix below, I now have the following results:
FINAL UPDATE
Final result looks like below. Many thanks to Plutonix for all the help!
I am trying to create a custom control
You didnt say whether this was subclassing a control (like Panel) or was built as a UserControl
. I am guessing the latter based on InitializeComponent()
.
The main thing seems to be that the standard Border for the UserControl
is still being painted. Add this to turn it off:
Public Sub New()
MyBase.BorderStyle = Windows.Forms.BorderStyle.None
...
You may want to hide that property so the end user cant turn it back on in Properties.
Also, with wider borders you will find that the bottom border is being clipped by one pixel (somewhat apparent in your image - the top horizontal appears thicker than the bottom one). Add this to your GetPath
method:
h As Int32 = rc.Height - 1
Result:
Also, BackColor
is inherited and applies to the entire client area, which remains a rectangle. You'll probably need to replace that as well. Leave the actual BackColor
as Transparent
, maybe hiding it that property from the user as well, and use a new FillColor
property:
' in the paint event
Using br As Brush = New SolidBrush(FillColor)
...
Using a FillColor
property and forcing BackColor
to Transparent
: