VB.NET Formサイズに合わせて各コントロールを自動スケーリング その2

# 解像度や画面サイズを意識しない画面レイアウト
端末の解像度やウィンドウサイズを意識せずに画面レイアウトを作成したいが、WinFormsのAnchorでは実現ができない。フォームサイズに合わせて自動で各コントロールのサイズを調整する仕組みをメモ

# 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
```

# 使い方
下記のようなベースフォームを作成する。
サイズを調整したいフォームにベースフォームを継承する。


```vb:BaseForm.vb
Public Class BaseForm
    Private resizeHelper As clsResize

    Public Sub New()
        InitializeComponent()
        OnLoad(EventArgs.Empty)
    End Sub

    Protected Overrides Sub OnLoad(e As EventArgs)
        If Not DesignMode Then
            MyBase.OnLoad(e)
            resizeHelper = New clsResize(Me)
            resizeHelper._get_initial_size()
        End If
    End Sub

    Protected Overrides Sub OnResize(e As EventArgs)
        If Not DesignMode Then
            If resizeHelper Is Nothing Then
                resizeHelper = New clsResize(Me)
                resizeHelper._get_initial_size()
            Else
                resizeHelper._resize()
            End If
        End If
    End Sub

End Class
```
```vb:Form1.Designer.vb
Partial Class Form1
    Inherits BaseForm

End Class
```