AutoSized, Wrapping RadioButton and CheckBox (VB)

The following RadioButton and CheckBox automatically text wrap when placed in a TableLayoutPanel or FlowLayoutPanel.

Imports System.Windows.Forms
Imports System.Collections
Imports System.Drawing
Imports System

Namespace Microsoft.Samples

    Friend Class WrappingCheckBox
Inherits System.Windows.Forms.CheckBox

        Dim cachedSizeOfOneLineOfText As System.Drawing.Size = System.Drawing.Size.Empty
Dim preferredSizeHash As New Dictionary(Of Size, Size)(3) ' testing this out - typically we've got three different constraints.

        Friend Sub New()
MyBase.New()
Me.AutoSize = True
End Sub

        Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)

            MyBase.OnTextChanged(e)
CacheTextSize()
End Sub

        Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs)
MyBase.OnFontChanged(e)
CacheTextSize()
End Sub

        Private Sub CacheTextSize()
'When the text has changed, the preferredSizeHash is invalid...
preferredSizeHash.Clear()

            If String.IsNullOrEmpty(Me.Text) Then
cachedSizeOfOneLineOfText = System.Drawing.Size.Empty
Else
cachedSizeOfOneLineOfText = TextRenderer.MeasureText(Me.Text, Me.Font, New Size(Int32.MaxValue, Int32.MaxValue), TextFormatFlags.WordBreak)
End If
End Sub

        Public Overrides Function getpreferredsize(ByVal proposedsize As System.Drawing.Size) As System.Drawing.Size

            Dim prefSize As Size = MyBase.GetPreferredSize(proposedsize)
If (proposedsize.Width > 1) AndAlso (prefSize.Width > proposedsize.Width) AndAlso (Not String.IsNullOrEmpty(Me.Text) AndAlso Not proposedsize.Width.Equals(Int32.MaxValue) OrElse Not proposedsize.Height.Equals(Int32.MaxValue)) Then
' we have the possiblility of wrapping... back out the single line of text
Dim bordersAndPadding As Size = prefSize - cachedSizeOfOneLineOfText
' add back in the text size, subtract baseprefsize.width and 3 from proposed size width so they wrap properly
Dim newConstraints As Size = proposedsize - bordersAndPadding - New Size(3, 0)

                If newConstraints.Width < 0 Then
newConstraints.Width = 0
End If
If newConstraints.Height < 0 Then
newConstraints.Height = 0
End If

                If (Not preferredSizeHash.ContainsKey(newConstraints)) Then
prefSize = bordersAndPadding + TextRenderer.MeasureText(Me.Text, Me.Font, newConstraints, TextFormatFlags.WordBreak)
preferredSizeHash(newConstraints) = prefSize

                Else
prefSize = preferredSizeHash(newConstraints)
End If
End If
Return prefSize
End Function
End Class

    Friend Class WrappingRadioButton
Inherits System.Windows.Forms.RadioButton

        Dim cachedSizeOfOneLineOfText As System.Drawing.Size = System.Drawing.Size.Empty
Dim preferredSizeHash As New Dictionary(Of Size, Size)(3) ' testing this out - typically we've got three different constraints.

        Friend Sub New()
MyBase.New()
Me.AutoSize = True
End Sub

        Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)

            MyBase.OnTextChanged(e)
CacheTextSize()
End Sub

        Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs)
MyBase.OnFontChanged(e)
CacheTextSize()
End Sub

        Private Sub CacheTextSize()
'When the text has changed, the preferredSizeHash is invalid...
preferredSizeHash.Clear()

            If String.IsNullOrEmpty(Me.Text) Then
cachedSizeOfOneLineOfText = System.Drawing.Size.Empty
Else
cachedSizeOfOneLineOfText = TextRenderer.MeasureText(Me.Text, Me.Font, New Size(Int32.MaxValue, Int32.MaxValue), TextFormatFlags.WordBreak)
End If
End Sub

        Public Overrides Function getpreferredsize(ByVal proposedsize As System.Drawing.Size) As System.Drawing.Size

            Dim prefSize As Size = MyBase.GetPreferredSize(proposedsize)
If (proposedsize.Width > 1) AndAlso (prefSize.Width > proposedsize.Width) AndAlso (Not String.IsNullOrEmpty(Me.Text) AndAlso Not proposedsize.Width.Equals(Int32.MaxValue) OrElse Not proposedsize.Height.Equals(Int32.MaxValue)) Then
' NOTE: WinForm pass (1,0) to ask the default size of the control, when it hasn't got prefered Width. We should prefer to arrange everything in one line, but not break to multilines.
' we have the possiblility of wrapping... back out the single line of text
Dim bordersAndPadding As Size = prefSize - cachedSizeOfOneLineOfText
' add back in the text size, subtract baseprefsize.width and 3 from proposed size width so they wrap properly
Dim newConstraints As Size = proposedsize - bordersAndPadding - New Size(3, 0)

                If newConstraints.Width < 0 Then
newConstraints.Width = 0
End If
If newConstraints.Height < 0 Then
newConstraints.Height = 0
End If

                If (Not preferredSizeHash.ContainsKey(newConstraints)) Then
prefSize = bordersAndPadding + TextRenderer.MeasureText(Me.Text, Me.Font, newConstraints, TextFormatFlags.WordBreak)
preferredSizeHash(newConstraints) = prefSize

                Else
prefSize = preferredSizeHash(newConstraints)
                End If
End If
Return prefSize
End Function
End Class
End Namespace