winformspowershelllayoutautosize

how to create dynamic layout since AutoSize in winforms doesn't work?


trying to create simple win form in PowerShell. there will be some automatically calculated checkbox and i'm struggling with sizes - seems that 'AutoSize' is a bullsh*t and values returned are from nowhere. can anyone please help and suggest how you create dynamic positioning? based on which values?

Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

$nrOfNIC = 2
$nrOfDisks = 3
$nrOfPIP = 1

$vShift = 20
$allChkb = 1


$chkForm = New-Object system.Windows.Forms.Form
$chkForm.text = "Remove Resources"
$chkForm.Font = New-Object System.Drawing.Font('Microsoft Sans Serif', 10)
$chkForm.AutoSize = $true
$chkForm.StartPosition = 'CenterScreen'
$chkForm.FormBorderStyle = 'Fixed3D'
$chkForm.Icon = [System.Drawing.SystemIcons]::Question
$chkForm.Topmost = $true
$chkForm.MaximizeBox = $false

$chkVMBox = new-object System.Windows.Forms.GroupBox
#$chkVMBox.MinimumSize = New-Object System.Drawing.Size(180,100) 
$chkVMBox.AutoSize = $true
$chkVMBox.Location = New-Object System.Drawing.Point(10,10)
$chkVMBox.Text = 'VM resources'
#$chkVMBox.Anchor = 'left,top'
#$lastControl = $chkVMBox

if($nrOfDisks -gt 0) {

    $chkVMDisks = new-object System.Windows.Forms.GroupBox
    #$chkVMDisks.MinimumSize = New-Object System.Drawing.Size(180,20) 
    $chkVMDisks.Location = New-Object System.Drawing.Point(10,20)
    $chkVMDisks.Text = 'DISKs'
    #$chkVMDisks.Anchor = 'left,top'

    for($disk=0;$disk -lt $nrOfDisks;$disk++) {

        $chkbDisk = New-Object System.Windows.Forms.Checkbox 
        $chkbDisk.Location = New-Object System.Drawing.Point(10, ($vShift+($disk*$vShift)) ) 
        #$chkbDisk.Anchor = 'left,top'
        $chkbDisk.AutoSize = $true
        $chkbDisk.Text = "disk $disk"
        $chkbDisk.TabIndex = $allChkb++
        $chkVMDisks.Controls.Add($chkbDisk)
        #$allChkb++
    }
    $chkVMBox.Controls.Add($chkVMDisks)
    #$lastControl=$chkVMDisks
}

if($nrOfNIC -gt 0) {
    #$vLocation = $lastControl.Bottom+$shift
    $vLocation = $chkVMDisks.Bottom+$shift

    $chkVMNICs = new-object System.Windows.Forms.GroupBox
    #$chkVMNICs.MinimumSize = New-Object System.Drawing.Size(180,20) 
    $chkVMNICs.AutoSize = $true
    $chkVMNICs.Location = New-Object System.Drawing.Point(10,$vLocation)
    $chkVMNICs.Text = 'NICs'
    #$chkVMNICs.Anchor = 'left,top'

    for($nic = 0;$nic -lt $nrOfNIC; $nic++) {
        $chkbNIC = New-Object System.Windows.Forms.Checkbox 
        $chkbNIC.Location = New-Object System.Drawing.Point(10, ($vShift+($nic*$vShift)) ) 
        #$chkbNIC.Anchor = 'left,top'
        $chkbNIC.AutoSize = $true
        $chkbNIC.Text = "nic $nic"
        $chkbNIC.TabIndex = $allChkb++
        $chkVMNICs.Controls.Add($chkbNIC)
        #$allChkb++
    }
    $chkVMBox.Controls.Add($chkVMNICs)
    #$lastControl = $chkVMNICs
}

    #$vLocation = $lastControl.Bottom+$shift
    $vLocation = $chkVMNICs.Bottom+$shift
    $chkbVMdiag = New-Object System.Windows.Forms.Checkbox 
    $chkbVMdiag.Location = New-Object System.Drawing.Point(10,$vLocation) 
    #$chkbVMdiag.Anchor = 'left,top'
    $chkbVMdiag.AutoSize = $true
    $chkbVMdiag.Text = "Boot Diagnostics"
    $chkbVMdiag.TabIndex = $allChkb++
    $chkVMBox.Controls.Add($chkbVMdiag)
    
    
    $vLocation = $chkVMBox.bottom + 40
    $btOK = New-Object System.Windows.Forms.Button
    $btOK.Location = New-Object System.Drawing.Size(15,$vLocation)
    $btOK.Size = New-Object System.Drawing.Size(70,20)
    $btOK.Text = "OK"
    $btOK.DialogResult = [System.Windows.Forms.DialogResult]::OK
    #$btOK.Anchor = 'left,bottom'

    $btCancel = New-Object System.Windows.Forms.Button
    $btCancel.Location = New-Object System.Drawing.Size(95,$vLocation)
    $btCancel.Size = New-Object System.Drawing.Size(70,20)
    $btCancel.Text = "Cancel"
    $btCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    #$btCancel.Anchor = 'right,bottom'     

$chkForm.AcceptButton = $btOK
$chkForm.CancelButton = $btCancel
$chkForm.Controls.AddRange(@($chkVMBox, $btOK, $btCancel))

[void]$chkForm.ShowDialog()

effect: effect of code

seems that ALL VALUES returned with 'autosize' are bullsh*t. so how do you create dynamic layout, not knowing sizes/number of elements upfront?


Solution

  • Set .AutoSizeMode = 'GrowAndShrink' as well as .MinimumSize properties along with the .AutoSize.

    Button positions are derived from $chkVMBox.bottom; use $chkForm.Controls.Add($chkVMBox) before computing vertical location for buttons and remove $chkVMBox from $chkForm.Controls.AddRange(…)

    I'd try calculating horizontal and vertical positions and (minimal) sizes of controls relative to an invariant; for instance, those are computed from $chkForm.Font in the following code (aspiration apparently inconsistent:), see the $hShift and $vShift variables, their values and usage.

    Add-Type -AssemblyName System.Drawing
    Add-Type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.Application]::EnableVisualStyles()
    Remove-Variable chk* -ErrorAction SilentlyContinue
    $nrOfNIC = 2
    $nrOfDisks = 3
    $nrOfPIP = 1
    $allChkb = 1
    
    $chkForm = New-Object System.Windows.Forms.Form
    $chkForm.text = "Remove Resources"
    $chkForm.Font = New-Object System.Drawing.Font('Microsoft Sans Serif', 10)
    $hShift  = $chkForm.Font.SizeInPoints
    $vShift  = $chkForm.Font.Height * 1.5  ### arbitrary ad hoc coefficient
    
    $chkForm.StartPosition = 'CenterScreen'
    $chkForm.FormBorderStyle = 'Fixed3D'
    $chkForm.Icon = [System.Drawing.SystemIcons]::Question
    $chkForm.Topmost = $true
    $chkForm.AutoSize = $true
    $chkForm.AutoSizeMode = 'GrowAndShrink'
    $chkForm.MinimumSize = [System.Drawing.Size]::new(100,100)
    # $chkForm.AutoScaleMode = 'Font'
    $chkForm.MaximizeBox = $false
    $chkForm.MinimizeBox = $false
    
    $chkVMBox = new-object System.Windows.Forms.GroupBox
    $chkVMBox.AutoSizeMode = 'GrowAndShrink'
    $chkVMBox.AutoSize = $true
    $chkVMBox.Location = New-Object System.Drawing.Point(10,10)
    $chkVMBox.Text = 'VM resources'
    
    if($nrOfDisks -gt 0) {
    
        $chkVMDisks = new-object System.Windows.Forms.GroupBox
        $chkVMDisks.Location = New-Object System.Drawing.Point($hShift,( $vShift+10))
        $chkVMDisks.Text = 'DISKs'
        $chkVMDisks.AutoSize = $true
        $chkVMDisks.MinimumSize = [System.Drawing.Size]::new(($chkVMBox.Size.Width - $hShift),$vShift)
        $chkVMDisks.AutoSizeMode = 'GrowAndShrink'
    
        for($disk=0;$disk -lt $nrOfDisks;$disk++) {
    
            $chkbDisk = New-Object System.Windows.Forms.Checkbox 
            $chkbDisk.Location = New-Object System.Drawing.Point($hShift, ($vShift*($disk+1)))
            $chkbDisk.AutoSize = $true
            $chkbDisk.Text = "disk $disk"
            $chkbDisk.TabIndex = $allChkb++
            $chkVMDisks.Controls.Add($chkbDisk)
            #$allChkb++
        }
        $chkVMBox.Controls.Add($chkVMDisks)
        #$lastControl=$chkVMDisks
    }
    
    if($nrOfNIC -gt 0) {
        #$vLocation = $lastControl.Bottom+$hShift
        $vLocation = $chkVMDisks.Bottom + $vShift
    
        $chkVMNICs = new-object System.Windows.Forms.GroupBox
        $chkVMNICs.AutoSize = $true
        $chkVMNICs.MinimumSize = [System.Drawing.Size]::new(($chkVMBox.Size.Width - $hShift),$vShift)
        $chkVMNICs.AutoSizeMode = 'GrowAndShrink'
        $chkVMNICs.Location = New-Object System.Drawing.Point($hShift,$vLocation)
        $chkVMNICs.Text = 'NICs'
    
        for($nic = 0;$nic -lt $nrOfNIC; $nic++) {
            $chkbNIC = New-Object System.Windows.Forms.Checkbox 
            $chkbNIC.Location = New-Object System.Drawing.Point($hShift, ($vShift*($nic+1)) ) 
            # $chkbNIC.Anchor = 'left,top'
            $chkbNIC.AutoSize = $true
            $chkbNIC.Text = "nic $nic"
            $chkbNIC.TabIndex = $allChkb++
            $chkVMNICs.Controls.Add($chkbNIC)
            #$allChkb++
        }
        $chkVMBox.Controls.Add($chkVMNICs)
        #$lastControl = $chkVMNICs
    }
    
        #$vLocation = $lastControl.Bottom+$hShift
        $vLocation = $chkVMNICs.Bottom + $vShift
        $chkbVMdiag = New-Object System.Windows.Forms.Checkbox 
        $chkbVMdiag.Location = New-Object System.Drawing.Point($hShift,$vLocation) 
        $chkbVMdiag.AutoSize = $true
        $chkbVMdiag.Text = "Boot Diagnostics"
        $chkbVMdiag.TabIndex = $allChkb++
        $chkVMBox.Controls.Add($chkbVMdiag)
        
    $chkForm.Controls.Add($chkVMBox)
        
        $vLocation = $chkVMBox.bottom + 20
        $btOK = New-Object System.Windows.Forms.Button
        $btOK.Location = New-Object System.Drawing.Point(15,$vLocation)
        # $btOK.Size = New-Object System.Drawing.Size(70,20)
        $btOK.AutoSize = $true
        $btOK.Text = "OK"
        $btOK.DialogResult = [System.Windows.Forms.DialogResult]::OK
    
        $btCancel = New-Object System.Windows.Forms.Button
        $btCancel.Location = New-Object System.Drawing.Point(95,$vLocation)
        # $btCancel.Size = New-Object System.Drawing.Size(70,20)
        $btCancel.AutoSize = $true
        $btCancel.Text = "Cancel"
        $btCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    
    $chkForm.AcceptButton = $btOK
    $chkForm.CancelButton = $btCancel
    $chkForm.Controls.AddRange(@($btOK, $btCancel))
    
    [void]$chkForm.ShowDialog()
    $chkForm.Dispose()