functionpowershellconstructorclass-constructors

powershell class constructor for form buttons


I have a powershell form that I am using to manage installed applications and offer a method of quickly uninstalling that app. What I am trying to do is create a class constructor for buttons on the form so I can enable or disable the state of the button on the form from another function. Below is what I am trying to do but I am open to other suggestions.

Add-Type -AssemblyName System.Windows.Forms

class App
{
    [string] $Name
    [bool] $Installed
    [string] $Key32
    [string] $Key64
    [string] $Inst_Dir
    [bool] $Current
    [string] $Exec
    [string] $User_Ver
    [string] $Inst_Ver

    App ([string] $Name, [bool] $Installed, [string] $Key32, [string] $Key64, [string] $Inst_Dir, [bool] $Current, [string] $Exec, [string] $User_Ver, [string] $Inst_Ver)
    {
        $this.Name = $Name
        $this.Installed = $Installed
        $this.Key32 = $Key32
        $this.Key64 = $Key64
        $this.Inst_Dir = $Inst_Dir
        $this.current = $Current
        $this.Exec = $Exec
        $this.User_Ver = $User_Ver
        $this.Inst_Ver = $Inst_Ver
    }
}

class Button
{    
    [string] $Text
    [int] $Width
    [int] $Height
    [string] $Font
    [bool] $Enabled

    Button ([string] $Text, [int] $Width, [int] $Height, [string] $Font, [bool] $Enabled)
    {
        $this.Text = $Text
        $this.Width = $Width
        $this.Height = $Height
        $this.Font = $Font
        $this.Enabled = $Enabled
    }
}

#region Define and initialize Variables
$HKLM32 = ".\SOFTWARE\Key Location"
$HKLM64 = ".\SOFTWARE\Wow6432Node\Key Location"

# Initialize app classes
[App] $TestApp= [App]::new("TestApp", $false, "$HKLM32\TestApp $TestApp_Ver", "$HKLM64\TestApp $TestApp_Ver", "", $false, "", $TestApp_Ver, "")

$apps = $TestApp

Function create_form()
{
    $Form = New-Object system.Windows.Forms.Form 
    $Form.Text = "Performance Test Auto Setup"
    $Form.TopMost = $true
    $Form.Width = 480
    $Form.Height = 300
    $Form.StartPosition = "CenterScreen"
    $Form.FormBorderStyle = "Fixed3D"
    $Form.MaximizeBox = $false
    $Form.MinimizeBox = $false

    [Button] $btnTestAppUninstall = [Button]::new("Uninstall", 95, 22, "Microsoft Sans Serif, 10", $true)
    New-Object System.Drawing.Point(285, 9)

    <#
    $btnTestAppUninstall = New-Object system.windows.Forms.Button 
    $btnTestAppUninstall.Text = "Uninstall"
    $btnTestAppUninstall.Width = 95
    $btnTestAppUninstall.Height = 22
    $btnTestAppUninstall.location = new-object system.drawing.point(285,9)
    $btnTestAppUninstall.Font = "Microsoft Sans Serif,10"
    $btnTestAppUninstall.Enabled = $false
    $Form.controls.Add($btnTestAppUninstall) 
    $btnTestAppUninstall.Add_Click({uninstallApp($TestApp.Inst_Dir)})
    #>

    $btnTest = New-Object system.windows.Forms.Button 
    $btnTest.Text = "test"
    $btnTest.Width = 95
    $btnTest.Height = 22
    $btnTest.location = new-object system.drawing.point(50,9)
    $btnTest.Font = "Microsoft Sans Serif,10"
    $Form.controls.Add($btnTest) 
    $btnTest.Add_Click({updateUI})


    $Form.ShowDialog() | Out-Null
}

Function updateUI()
{
    $apps | ForEach-Object {$app = [string]("$"+"btn$($_.Name)Uninstall")}
    Write-Host  $app.GetType() $btnTestAppUninstall.GetType()
}


create_Form 

The commented out section in the middle of the form create is how I was originally creating the button at form create which works fine. The issue is from adjusting the button.Enabled stated of that button from another function that uses a foreach-object loop on the $apps array. I have slimmed down this snipped to just a single button on a form that when launched will show a test button but nothing else as the class constructor does not create a button. The test button function "updateUI" is why I am trying to do it this way since when creating the button variable name the way I was is creating a "string" not an "system.drawings.button" object so I cannot access the enabled property.

I hope what I am trying to do here is clear and can answer any questions. I apologize for the sloppy half worked on code so here is the snippet before I started working on the class constructor where I have a button but cannot change the state.

Add-Type -AssemblyName System.Windows.Forms

class App
{
    [string] $Name
    [bool] $Installed
    [string] $Key32
    [string] $Key64
    [string] $Inst_Dir
    [bool] $Current
    [string] $Exec
    [string] $User_Ver
    [string] $Inst_Ver

    App ([string] $Name, [bool] $Installed, [string] $Key32, [string] $Key64, [string] $Inst_Dir, [bool] $Current, [string] $Exec, [string] $User_Ver, [string] $Inst_Ver)
    {
        $this.Name = $Name
        $this.Installed = $Installed
        $this.Key32 = $Key32
        $this.Key64 = $Key64
        $this.Inst_Dir = $Inst_Dir
        $this.current = $Current
        $this.Exec = $Exec
        $this.User_Ver = $User_Ver
        $this.Inst_Ver = $Inst_Ver
    }
}

#region Define and initialize Variables
$HKLM32 = ".\SOFTWARE\Key Location"
$HKLM64 = ".\SOFTWARE\Wow6432Node\Key Location"

# Initialize app classes
[App] $TestApp = [App]::new("TestApp", $false, "$HKLM32\TestApp $TestApp_Ver", "$HKLM64\TestApp $TestApp_Ver", "", $false, "", $TestApp_Ver, "")

$apps = $TestApp

Function create_form()
{
    $Form = New-Object system.Windows.Forms.Form 
    $Form.Text = "Performance Test Auto Setup"
    $Form.TopMost = $true
    $Form.Width = 480
    $Form.Height = 300
    $Form.StartPosition = "CenterScreen"
    $Form.FormBorderStyle = "Fixed3D"
    $Form.MaximizeBox = $false
    $Form.MinimizeBox = $false

    $btnTestAppUninstall = New-Object system.windows.Forms.Button 
    $btnTestAppUninstall.Text = "Uninstall"
    $btnTestAppUninstall.Width = 95
    $btnTestAppUninstall.Height = 22
    $btnTestAppUninstall.location = new-object system.drawing.point(285,9)
    $btnTestAppUninstall.Font = "Microsoft Sans Serif,10"
    $btnTestAppUninstall.Enabled = $false
    $Form.controls.Add($btnTestAppUninstall) 
    $btnTestAppUninstall.Add_Click({uninstallApp($TestApp.Inst_Dir)})

    $btnTest = New-Object system.windows.Forms.Button 
    $btnTest.Text = "test"
    $btnTest.Width = 95
    $btnTest.Height = 22
    $btnTest.location = new-object system.drawing.point(50,9)
    $btnTest.Font = "Microsoft Sans Serif,10"
    $Form.controls.Add($btnTest) 
    $btnTest.Add_Click({updateUI})


    $Form.ShowDialog() | Out-Null
}

Function updateUI()
{
    $apps | ForEach-Object {$app = [string]("$"+"btn$($_.Name)Uninstall")}
    Write-Host  $app.GetType() $btnTestAppUninstall.GetType()
}


create_Form 

It is also worth noting that I know I can directly adjust the state using

$btnTestAppUninstall.Enabled = $true

or

$btnTestAppUninstalled.Enabled = $false

That is not however an optimal solution as the reason I am trying solve this problem is because every button on the form has to have these two options in multiple places throughout the updateUI function and there are 22 buttons on the real form. That is a lot of DRY being broken there. If I can make this work I can simply loop through everything with a foreach-object loop and set the state based on the stored value in the class object.

Any help is appreciated I have been trying to figure this out for a couple of days.


Solution

  • So I eventually abandoned this method and went with a good old for loop. What I did was create dynamic lists based on what is enabled in the form then I loop through lists simultaneously using the index number to put the appropriate value to the appropriate object.

    Function updateVersions()
    {   
        for($i = 0; $i -lt $apps.Length; $i++)
        {
            If(prop32Bit($apps[$i].Key32) -Not $Null)
            {
                $apps[$i].Inst_Dir = $appDir
                $apps[$i].Exec = (Get-ItemProperty -Path $apps[$i].Key32)."Application Name"
                $apps[$i].Ver = (Get-ItemProperty -Path $apps[$i].Key32).Version
                $apps[$i].Installed = $true
            }
            ElseIf (prop64Bit($apps[$i].Key64) -Not $Null)
            {
                $apps[$i].Inst_Dir = $appDir
                $apps[$i].Exec = (Get-ItemProperty -Path $apps[$i].Key64)."Application Name"
                $apps[$i].Inst_Ver = (Get-ItemProperty -Path $apps[$i].Key64).Version
                $apps[$i].Installed = $true
            }
            Else
            {
                $apps[$i].Inst_Dir = $Null
                $apps[$i].Exec = $Null
                $apps[$i].Inst_Ver = "Not Installed"
                $apps[$i].Installed = $false
            }
        }
    
        # Update version labels
        For($i = 0; $i -lt $listVerLbls.Length; $i++)
        {
            $listVerLbls[$i].Text = $apps[$i].Inst_Ver        
        }
    
        # Update uninstall buttons
        For($i = 0; $i -lt $listUninBtns.Length; $i++)
        {
            If($apps[$i].installed)
            {
                $listUninBtns[$i].Enabled = $true
            }
            Else
            {
                $listUninBtns[$i].Enabled = $false
            }
        }
    
        # Update current buttons
        For($i = 0; $i -lt $listCurBtns.Length; $i++)
        {
            If($apps[$i].installed)
            {
                $listCurBtns[$i].Enabled = $true
                $listCurBtns[$i].BackColor = "DarkRed"
                $listCurBtns[$i].ForeColor = "White"
            }
            Else
            {
                $listCurBtns[$i].Enabled = $false
                $listCurBtns[$i].BackColor = "Control"
                $listCurBtns[$i].ForeColor = "ControlDark"
            }
        }
    }
    

    This works perfectly for what I was trying to do.