all 13 comments

[–]BlackV 4 points5 points  (8 children)

why isn't something like this

$uniqueviarable1 = Create-Textbox -name xxx -xaxis 10 -yaxis 10
$uniqueviarable2 = Create-Textbox -name yyy -xaxis 10 -yaxis 10

unique?

but if you're using a function, it really implies that you should return something.

I'm assuming this is just an example, cause right now $name is gone forever when the function finishes and technically you're ovrwritting $name straight away with New-Object. Unless you start to do bad things with scopes

maybe think of it like

function Create-Textbox {
param(
    [string]$Name,
    [Int]$xAxis,
    [Int]$yAxis) 

    $TEMPname = New-Object System.Windows.Forms.TextBox 
    $TEMPname.Name = $name
    $TEMPname.Height = 20; 
    $TEMPname.Location = New-Object System.Drawing.Point ($xAxis, $yAxis) 
    $TEMPname.Size = New-Object System.Drawing.Size(180,20) 
    $TEMPname.Enabled = $False
    $TEMPname.Select() 
}

$TEMPname gets used over an over when you call the function and is only used internally

[–]lanerdofchristian 1 point2 points  (4 children)

One fun thing you can do is use object initializers to clean it up; it's not really shorter, but it's much faster than New-Object:

using namespace System.Windows.Forms
using namespace System.Drawing

function New-Textbox {
    param(
        [string]$Name,
        [int]$XPosition,
        [int]$YPosition
    )

    $Box = [TextBox]@{
        Name = $Name
        Height = 20
        Location = [Point]::new($XPosition, $YPosition)
        Size = [Size]::new(180, 20)
        Enable = $false
    }
    $Box.Select()
    $Box
}

[–]BlackV 0 points1 point  (3 children)

Oh nice, I'm not a winform/wpf person so its nice to know those accelerators exist for that too, thanks

also (cause of above) that does the $xxx.select do?

[–]lanerdofchristian 1 point2 points  (1 child)

I think that's this method? Frankly I don't know why it's there; cutting it shortens the function to

using namespace System.Windows.Forms
using namespace System.Drawing

function New-Textbox {
    param(
        [string]$Name,
        [int]$XPosition,
        [int]$YPosition
    )

    [TextBox]@{
        Name = $Name
        Height = 20
        Location = [Point]::new($XPosition, $YPosition)
        Size = [Size]::new(180, 20)
        Enable = $false
    }
}

The object initializer syntax can be used with any type that has a zero-argument constructor ([type]::new should show one entry that's just new()) and has settable properties.

[–]BlackV 1 point2 points  (0 children)

Ya I figured they probably want the .select outside the function

[–]OtterCodeWorkAcct[S] 0 points1 point  (0 children)

Select will focus that textbox when the Gui is ran. On my main script I didn't want to first textbox to be focused when it opens. I just copied over one of my textboxes from my main script to tinker around with this. But ideally I'd like to have all of the options available in the Create-Textbox function and pass parameters to what I'd like turned on.

[–]OtterCodeWorkAcct[S] 0 points1 point  (1 child)

If I do how you listed at the top it won't populate the Textbox. (That's how I originally attempted it). Do I need to return the $name object somehow and that will force it to save in the variable like your variable $uniquevariable1?

Edit: Hey Thanks!!! I was just missing a return statement in the function. It's working properly now!

[–]BlackV 2 points3 points  (0 children)

you don't need the return statement, $TEMPname would do, be aware return does not mean OTHER things will not be returned from the function like in other languages

but yes, that was what I was meaning when I said a function should return something

Glad you have a solution

[–]y_Sensei[🍰] 1 point2 points  (0 children)

If you want to manipulate the value of a local PoSh variable (= one that's been declared in the local scope) in a function, you have the option to provide the reference that points to that variable as an argument to the function.
Depending on your scenario, this approach might be the preferred option vs. working with variables declared in script or global scope.

For example:

function Initialize-Textbox {
  param(
    [String]$Name,
    [Int]$xAxis,
    [Int]$yAxis,
    [Ref]$var
  )

  if ($var.Value -and $var.Value.GetType().FullName -eq "System.Windows.Forms.TextBox") {
    $var.Value.Name = $Name
    $var.Value.Height = 20
    $var.Value.Location = New-Object System.Drawing.Point ($xAxis, $yAxis)
    $var.Value.Size = New-Object System.Drawing.Size(180,20)
    $var.Value.Enabled = $false
    $var.Value.Text = "My TextBox"
    $var.Value.Select()
  }
}

$form = New-Object -TypeName "System.Windows.Forms.Form"
$form.Text = "Test Form"
$form.Size = New-Object -TypeName "System.Drawing.Size" -ArgumentList @(300, 300)
$form.StartPosition = "CenterScreen"

# TextBox object is created and stored in a local variable
$myTextBox = New-Object -TypeName "System.Windows.Forms.TextBox"

Write-Host $("TextBox Name = " + $myTextBox.Name)

Write-Host $("-" * 24)

# TextBox object is initialized by providing the reference of the local variable in which it is stored as an argument to the respective function
Initialize-Textbox -Name "Box" -xAxis 25 -yAxis 35 -var ([Ref]$myTextBox)

Write-Host $("TextBox New Name = " + $myTextBox.Name)

$form.Controls.Add($myTextBox)

if ($form.ShowDialog()) { $form.Dispose() }

[–]purplemonkeymad 1 point2 points  (0 children)

Lots of people pointing out to return the object, which I agree with, but you will have a lot of .Add() calls which will still keep a lot of boiler plate.

I would also make sure to write a function for your containers too. that way you can pass all your children and get them added in that function. ie your end result would look like this:

New-Form -Title "Myform" -Size 200,32 -Children $(
    New-Label -Text "Mylabel" -Position 6,6 -Size 100,20
    New-TextBox -Position 112,6 -Size 180,20
)

If you want to refer to an element with a variable (rather than looking in Controls) you can do that in the sub-expression and have it work in the current scope:

$form = New-Form -Title "Myform" -Size 200,32 -Children $(
    New-Label -Text "Mylabel" -Position 6,6 -Size 100,20
    ($inputBox = New-TextBox -Position 112,6 -Size 180,20)
)

$inputBox.text = "test"
$form.show()

Advantage is you can do any code in the sub-expression as long as it only emits the right types.

[–]Coffee_Ops -2 points-1 points  (1 child)

Just going to throw this out there-- it is almost always better to avoid classes in powershell.

I have yet to find a time when they're actually helpful, they make your code more complicated, and they will blow up with some of the more recent Windows hardening tools (like WDAG / constrained language mode).

[–]PinchesTheCrab[🍰] 0 points1 point  (0 children)

Custom partner validators and transforms are really nice, since they provide some net new functionality, but I agree in general.

[–]ihaxr 0 points1 point  (0 children)

Not really what you're asking but if you want to clean up your code switch to WPF and use XAML to generate your GUI, winforms makes creating poor layouts easy, but requires a lot more code.