VB 画面サイズに合わせて自由にControlsをリサイズ

# 解像度や画面サイズを意識しない画面レイアウト
端末の解像度やウィンドウサイズを意識せずに画面レイアウトを作成したいが、WinFormsのAnchorでは実現ができない。フォームサイズに合わせて自動で各コントロールのサイズを調整する必要があるが調べたところ既にC#公開されている方がいたのでそれをそのままVBにしたのを備忘録として残す。
![TestForm1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676943/621f2941-0c19-ab18-74b5-0b689447b867.png)![TestForm2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676943/f5ecd515-bca3-c20a-6f31-04a59fad67be.png)
# 参考
オリジナル
　[C# Resize ALL Controls at Runtime](https://www.codeproject.com/Tips/749619/Csharp-Resize-ALL-Controls-at-Runtime)
上記のカスタム
　[C# 画面サイズに合わせて自由にControlsをリサイズ](https://qiita.com/jh178bz/items/3b030e127f0d8fdce15d)

# Resizeクラス
下記クラスを作成する。
```vb:clsResize.vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms

Public Class clsResize
    Private _arr_control_storage As List(Of System.Drawing.Rectangle) = New List(Of System.Drawing.Rectangle)()
    Private showRowHeader As Boolean = False
    Private FontTable As Dictionary(Of String, Single)
    Private ControlTable As Dictionary(Of String, System.Drawing.Rectangle)

    Public Sub New(ByVal _form_ As Form)
        form = _form_
        _formSize = _form_.ClientSize
        _fontsize = _form_.Font.Size

        Dim _controls = _get_all_controls(form)
        FontTable = New Dictionary(Of String, Single)()
        ControlTable = New Dictionary(Of String, System.Drawing.Rectangle)()

        For Each control As Control In _controls
            FontTable.Add(control.Name, control.Font.Size)
            ControlTable.Add(control.Name, control.Bounds)
        Next
    End Sub

    Private _fontsize As Single
    Private _formSize As System.Drawing.SizeF
    Private form As Form

    Public Sub _get_initial_size()
        Dim _controls = _get_all_controls(form)

        For Each control As Control In _controls
            _arr_control_storage.Add(control.Bounds)
            If control.[GetType]() = GetType(DataGridView) Then _dgv_Column_Adjust((CType(control, DataGridView)), showRowHeader)
        Next
    End Sub

    Public Sub _resize()
        Dim _form_ratio_width As Double = CDbl(form.ClientSize.Width) / CDbl(_formSize.Width)
        Dim _form_ratio_height As Double = CDbl(form.ClientSize.Height) / CDbl(_formSize.Height)
        Dim _controls = _get_all_controls(form)
        Dim _pos As Integer = -1

        For Each control As Control In _controls
            Me._fontsize = FontTable(control.Name)
            _pos += 1
            Dim _controlSize As System.Drawing.Size = New System.Drawing.Size(CInt((_arr_control_storage(_pos).Width * _form_ratio_width)), CInt((_arr_control_storage(_pos).Height * _form_ratio_height)))
            Dim _controlposition As System.Drawing.Point = New System.Drawing.Point(CInt((_arr_control_storage(_pos).X * _form_ratio_width)), CInt((_arr_control_storage(_pos).Y * _form_ratio_height)))
            control.Bounds = New System.Drawing.Rectangle(_controlposition, _controlSize)
            If control.[GetType]() = GetType(DataGridView) Then _dgv_Column_Adjust((CType(control, DataGridView)), showRowHeader)
            control.Font = New System.Drawing.Font(form.Font.FontFamily, CSng((((Convert.ToDouble(_fontsize) * _form_ratio_width) / 2) + ((Convert.ToDouble(_fontsize) * _form_ratio_height) / 2))))
        Next
    End Sub

    Private Sub _dgv_Column_Adjust(ByVal dgv As DataGridView, ByVal _showRowHeader As Boolean)
        Dim intRowHeader As Integer = 0
        Const Hscrollbarwidth As Integer = 5

        If _showRowHeader Then
            intRowHeader = dgv.RowHeadersWidth
        Else
            dgv.RowHeadersVisible = False
        End If

        For i As Integer = 0 To dgv.ColumnCount - 1
            If dgv.Dock = DockStyle.Fill Then
                dgv.Columns(i).Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount)
            Else
                dgv.Columns(i).Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount)
            End If
        Next
    End Sub

    Private Shared Function _get_all_controls(ByVal c As Control) As IEnumerable(Of Control)
        Return c.Controls.Cast(Of Control)().SelectMany(Function(item) _get_all_controls(item)).Concat(c.Controls.Cast(Of Control)()).Where(Function(control) control.Name <> String.Empty)
    End Function
End Class
```

# 使い方
①LoadイベントでResizeクラスの_get_initial_sizeを呼ぶ
②SizeChangedイベントでResizeクラスの_resizeを呼ぶ
```vb:TestForm.vb
Public Class TestForm

    Private _form_resize As clsResize

    Public Sub New()
        InitializeComponent()

        _form_resize = New clsResize(Me)
        AddHandler Me.Load, AddressOf TestForm_Load
        AddHandler Me.SizeChanged, AddressOf TestForm_SizeChanged
    End Sub

    Private Sub TestForm_Load(sender As Object, e As EventArgs)
        _form_resize._get_initial_size()
    End Sub

    Private Sub TestForm_SizeChanged(sender As Object, e As EventArgs)
        _form_resize._resize()
    End Sub

End Class
```