I am trying to create an animated collapsible panel that consists of three different elements. Each element is created from a panel container that sits on a user control. It is made up of a header panel, a content panel and a footer panel (with the footer panel sitting inside the content panel):
Within each panel I override the draw event and do my own custom drawing. This includes rounding the corners, drawing a border, and filling the background (and drawing text in the cases of the header and footer).
The control also allows users to embed into the content panel at both design time and runtime.
When placed on a form, it looks exactly how I want it to, however, I cannot seem to animate the panel in a seamless 'smooth' transition. It is jerky, jittery and looks horrendous when expanding the panel (even with no content).
The way it should work is that when minimized, the content panel (including the footer panel) shrinks to only be the height of the header panel. The header panel then redraws itself to look different. Then when maximized, the panel basically does everything in reverse.
My animation code looks like such:
Dim m_Height As Integer = Me.Height
Dim m_HeaderHeight As Integer = 40
Dim m_FooterHeight As Integer = 35
Dim ShrinkStepSize As Integer = CInt((m_Height - m_HeaderHeight) / 10)
Dim ExpandStepSize As Integer = CInt((m_Height - m_HeaderHeight) / 4)
Private Sub picMinimize_Click(sender As Object, e As EventArgs) Handles picMinimize.Click
While (Me.Height > m_HeaderHeight)
Me.Height -= Math.Min(Me.Height - m_HeaderHeight, ShrinkStepSize)
Application.DoEvents()
End While
picMaximise.Visible = True
picMinimize.Visible = False
m_Minimized = True
Me.Invalidate(pnlHeader.ClientRectangle, True)
End Sub
Private Sub picMaximise_Click(sender As Object, e As EventArgs) Handles picMaximise.Click
While (Me.Height < m_Height)
Me.Height += Math.Min(m_Height - Me.Height, ExpandStepSize)
Application.DoEvents()
End While
picMaximise.Visible = False
picMinimize.Visible = True
m_Minimized = False
Me.Invalidate(pnlHeader.ClientRectangle, True)
End Sub
And without posting all of my code (unless it's required), here are all my paint events for the header, content and footer panels:
Private Sub pnlHeader_Paint(sender As Object, e As PaintEventArgs) Handles pnlHeader.Paint
Dim rect As Rectangle = pnlHeader.ClientRectangle
rect.X = rect.X + 1
rect.Y = rect.Y + 1
rect.Width -= 2
rect.Height -= 2
'Position the icon elements
picClose.Location = New Point(rect.Width - (picClose.Width + 8), CInt(((rect.Height - picClose.Height) / 2) + 3))
picOptions.Location = New Point(rect.Width - ((picClose.Width + picOptions.Width) + 10), CInt(((rect.Height - picOptions.Height) / 2) + 2))
picMinimize.Location = New Point(rect.Width - ((picMinimize.Width + picOptions.Width + picClose.Width) + 15), CInt(((rect.Height - picMinimize.Height) / 2) + 3))
picMaximise.Location = New Point(rect.Width - ((picMaximise.Width + picOptions.Width + picClose.Width) + 15), CInt(((rect.Height - picMaximise.Height) / 2) + 3))
Dim path As Drawing2D.GraphicsPath = RoundRectangle(rect, CornerRadius, Me.CornerRounding)
If m_Minimized Then
'Draw the background
Using br As Brush = New SolidBrush(Color.White)
e.Graphics.FillPath(br, path)
End Using
'Draw the border
Using br As Brush = New SolidBrush(BorderColour)
e.Graphics.DrawPath(New Pen(br, 1), path)
End Using
End If
'Draw the text
Dim textRect As Rectangle = rect
textRect.X += m_HeaderAdjustment
Using string_format As New StringFormat()
string_format.Alignment = StringAlignment.Near
string_format.LineAlignment = StringAlignment.Center
e.Graphics.DrawString(HeaderText, New Font("Segoe UI", 13, FontStyle.Bold, GraphicsUnit.Pixel), New SolidBrush(Color.FromArgb(157, 159, 162)), textRect, string_format)
End Using
End Sub
Private Sub pnlContent_Paint(sender As Object, e As PaintEventArgs) Handles pnlContent.Paint
Dim rect As Rectangle = pnlContent.ClientRectangle
rect.X = rect.X + 1
rect.Y = rect.Y + 1
rect.Width -= 2
rect.Height -= 2
Dim path As Drawing2D.GraphicsPath = RoundRectangle(rect, CornerRadius, Me.CornerRounding)
'Draw the background
Using br As Brush = New SolidBrush(Color.White)
e.Graphics.FillPath(br, path)
End Using
'Draw the border
Using br As Brush = New SolidBrush(BorderColour)
rect.Inflate(-1, -1)
e.Graphics.DrawPath(New Pen(br, 1), path)
End Using
End Sub
Private Sub pnlFooter_Paint(sender As Object, e As PaintEventArgs) Handles pnlFooter.Paint
Dim rect As Rectangle = pnlFooter.ClientRectangle
rect.X = rect.X + 1
rect.Y = rect.Y + 1
rect.Width -= 2
rect.Height -= 2
Dim rounding As Corners = Corners.BottomLeft Or Corners.BottomRight
Dim path As Drawing2D.GraphicsPath = RoundRectangle(rect, CornerRadius, rounding)
'Draw the background
Using br As Brush = New SolidBrush(FooterBackColour)
e.Graphics.FillPath(br, path)
End Using
'Draw the border
Using br As Brush = New SolidBrush(BorderColour)
e.Graphics.DrawPath(New Pen(br, 1), path)
End Using
'Draw the text
Dim textRect As Rectangle = rect
textRect.X += m_FooterAdjustment
textRect.Y += 1
Using string_format As New StringFormat()
string_format.Alignment = StringAlignment.Near
string_format.LineAlignment = StringAlignment.Center
e.Graphics.DrawString(FooterText, New Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Pixel), New SolidBrush(FooterForeColour), textRect, string_format)
End Using
End Sub
Any help with this would be greatly appreciated. Thanks heaps.