【问题标题】:Powershell GUI auto generate buttons with functionsPowershell GUI 自动生成具有功能的按钮
【发布时间】:2021-01-20 21:22:41
【问题描述】:

TLDR: 如何生成生成的变量,然后稍后在 Add_click 中调用该变量。 我确信我需要对每个对象/按钮进行某种序列化。

我正在构建一个从 csv 读取数据以创建按钮和功能的小工具。

csv 看起来像

Name  Type  Link  Script
Powershell App C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Empty
FixXYZ Fix Empty -ScriptStuffHere- 

然后该工具将创建一个带有名称的按钮(正在进行过滤应用程序和修复程序),当您单击该按钮时,如果它的应用程序将执行 start ($link) 并且如果它的修复程序将运行脚本。

我的问题是我让它制作按钮并给它们命名,按钮的名称保持不变,但功能没有。

完整代码:

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

#=======================================================

$Form                            = New-Object system.Windows.Forms.Form
$Form.text                       = "Form"
$Form.TopMost                    = $false
$Form.ClientSize                 = New-Object System.Drawing.Point(760,400)
$Form.minimumSize                = New-Object System.Drawing.Size(760,400) 
$Form.maximumSize                = New-Object System.Drawing.Size(760,400) 

$GetCSV = import-csv "C:\File.csv"
$Details = $GetCSV.Name

$DeviceList = $GetCSV

$Count = $DeviceList.Lines.Count
$ObjectNumber = -1
Write-Host "Total Entries:" $Count


$x = 0 #up down
$z = 0 #left right


$Names = @($DeviceList.Lines)
$Names | ForEach-Object{
$ObjectNumber += 1
Write-Host "Object:" $ObjectNumber 

$x += 0
$z += 120

if($z -eq 720){
$x += 120
$z = 0
Write-Host "New Row"}



Write-Host "x" $x
Write-Host "z" $z
$ButtonLabel = ($GetCSV[$ObjectNumber]).Name

set-Variable -Name "var$ObjectNumber" -Value ($GetCSV[$ObjectNumber] | Select Name, Type, Link, Script, File, FileSource)

Write-Host "Name: " (Get-Variable -Name "var$ObjectNumber" -ValueOnly).Name
Write-Host "Type: " (Get-Variable -Name "var$ObjectNumber" -ValueOnly).Type
Write-Host "Link: "(Get-Variable -Name "var$ObjectNumber" -ValueOnly).Link
Write-Host "Script: "(Get-Variable -Name "var$ObjectNumber" -ValueOnly).Script
Write-Host "File: "(Get-Variable -Name "var$ObjectNumber" -ValueOnly).File
Write-Host =========================

         
$_                         = New-Object system.Windows.Forms.Button
$_.text                    = $ButtonLabel
$_.width                   = 100
$_.height                  = 100
$_.location                = New-Object System.Drawing.Point($z,$x)
$_.Font                    = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
$_.Add_Click({              Start (Get-Variable -Name "var$ObjectNumber" -ValueOnly).Link})

$Form.Controls.Add($_)

}

[void]$Form.ShowDialog()

我很确定我的问题来自 $_.Add_Click({Start (Get-Variable -Name "var$ObjectNumber" -ValueOnly).Link})

我知道问题出在 $ObjectNumber 上,因为每次通过 ForEach 时该数字都会增加 +1,因此当我单击一个按钮时,它会将“var$OjbectNumber”作为其最后一个数字。单击按钮有效,但所有按钮都会打开最后一个条目链接。

【问题讨论】:

  • 那个文件真的是这样吗???如果是这样,那不是格式正确的 Csv,您也没有在 Import-Csv 工作中指定分隔符。您没有处理多个空格等。这个$DeviceList.Lines.Count 无效,The property 'Lines' cannot be found on this object. Verify that the property exists. 这个$x += 0,也永远不会被设置。只是好奇。但是,当您可以通过函数名调用 WPF/XAML 和点源代码文件时,为什么要使用 CSV?您还有其他错误。由于上述和使用的逻辑,那个 addClick 也是错误的。

标签: winforms powershell


【解决方案1】:

继续我的评论...

一个小重构,让它显示事物的位置

Clear-Host 

Add-Type -AssemblyName System.Windows.Forms,
                       PresentationFramework

[System.Windows.Forms.Application]::EnableVisualStyles()

$Form             = New-Object system.Windows.Forms.Form
$Form.text        = 'Form'
$Form.TopMost     = $false
$Form.ClientSize  = New-Object System.Drawing.Point(760,400)
$Form.minimumSize = New-Object System.Drawing.Size(760,400) 
$Form.maximumSize = New-Object System.Drawing.Size(760,400) 

$GetCSV       = Import-Csv -LiteralPath 'D:\Scripts\File.csv'
$Details      = $GetCSV.Name
$DeviceList   = $GetCSV
$Count        = $DeviceList.Count
$ObjectNumber = -1
 "Total Entries: $Count`n`n"

$ObjDown  = 0
$ObjRight = 0

$DeviceList.Name | 
ForEach-Object{
    $ObjectNumber += 1
    "`nObject: $ObjectNumber"

    $x        = 0
    $ObjRight = 120

    if($ObjRight -eq 720)
    {
        $x        = 120
        $ObjRight = 0
        'New Row'
    }


    "x $x"
    "z $ObjRight"

    $ButtonLabel = ($GetCSV[$ObjectNumber]).Name

    set-Variable -Name $("var$ObjectNumber") -Value ($GetCSV[$ObjectNumber] | 
    Select Name, Type, Link, Script, File, FileSource)

    ("Name:   $((Get-Variable -Name $("var$ObjectNumber") -ValueOnly).Name)")
    ("Type:   $((Get-Variable -Name $("var$ObjectNumber") -ValueOnly).Type)")
    ("Link:   $((Get-Variable -Name $("var$ObjectNumber") -ValueOnly).Link)")
    ("Script: $((Get-Variable -Name $("var$ObjectNumber") -ValueOnly).Script)")
    ("File:   $((Get-Variable -Name $("var$ObjectNumber") -ValueOnly).File)")
         
    $PSitem          = New-Object system.Windows.Forms.Button
    $PSitem.text     = $ButtonLabel
    $PSitem.width    = 100
    $PSitem.height   = 100
    $PSitem.location = New-Object System.Drawing.Point($ObjRight,$x)
    $PSitem.Font     = New-Object System.Drawing.Font('Microsoft Sans Serif',10)

    $PSitem.Add_Click({
        $(Get-Variable -Name $("var$ObjectNumber") -ValueOnly)
    })
    $Form.Controls.Add($PSitem)
}

#[void]$Form.ShowDialog()

这是我在另一篇帖子中给出的一个示例,用于动态创建 UX/UI 元素并分配表单事件,虽然不使用外部文件,但它是相同的概念。

How to create multiple button with PowerShell?

添加工具提示和表单事件,像这样...

$Form                            = New-Object system.Windows.Forms.Form
$Form.ClientSize                 = New-Object System.Drawing.Point(381,316)
$Form.text                       = "Auto Button UI"
$Form.TopMost                    = $false
$Form.BackColor                  = [System.Drawing.ColorTranslator]::FromHtml("#c9f6fe")

$i = 0
Get-Variable -Name 'Button*' | 
Remove-Variable

$objTooltip = New-Object System.Windows.Forms.ToolTip 
$objTooltip.InitialDelay = 100 

1..3 | 
foreach{
    $CurrentButton          = $null
    $CurrentButton          = New-Object System.Windows.Forms.Button
    $CurrentButton.Location = "$(50+100*$i), 275"
    $CurrentButton.Text     = $PSItem
    $CurrentButton.Font     = New-Object System.Drawing.Font('Microsoft Sans Serif',10)
    
    New-Variable "Button$PSitem" $CurrentButton

    $objTooltip.SetToolTip(
        $CurrentButton, 
        "Execute action assigned to $($CurrentButton.Text)"
    )

    $CurrentButton.add_click(
    {
        [System.Windows.Forms.MessageBox]::
        Show(
            "$($CurrentButton.Text)", $($CurrentButton.Text), [System.Windows.Forms.MessageBoxButtons]::
            OKCancel, [System.Windows.Forms.MessageBoxIcon]::Information
        )
    })

    $i++
    $form.Controls.Add($CurrentButton)
}

[void]$Form.ShowDialog()

然而,虽然它将事件添加到每个按钮元素,但消息文本是最后一个传递的。除非在链接中的示例中明确调用。

【讨论】:

  • 所以这就是我感到困惑的原因,在你给出的那个例子中,工具提示与按钮编号/名称相关,但是当你点击它时,它会显示一个带有最后一个按钮名称的弹出窗口无论我点击什么按钮。但是工具提示和按钮信息都与 $($CurrentButton.Text) 调用相同。为什么在工具提示存在时消息框中的内容不能正确显示?
  • 我的样本指向限制。基于文本的东西很容易处理/操作,事件是 1:1 的东西/静态分配。使用的事件变量名称只能是一个特定的对象名称。所以,你在事件中所追求的,我不可能知道(而且我确实尝试了一些事情)或从未见过其他人尝试过;也没有任何 UX/UI 开发人员参考、MSDocs 或 3rdP 文档解决了我能找到的这样一个用例。
  • 这是有道理的。我会尝试找到一种不同的方式来自动填充我的按钮。
  • 请记住,这里的交易是这条线$CurrentButton = New-Object System.Windows.Forms.Button,即catch22。它必须是独一无二的。这意味着必须为您创建的每个元素退出,因此您只能看到最后一个元素,因为每个循环,它都会与下一个项目一起重新创建。每个名称一个对象。最后,这个$form.Controls.Add($CurrentButton) 需要通过.AddRange.Add 添加每个。同样,该名称是静态的,当然,将其固定到该对象/元素所需的事件。
【解决方案2】:

答案是使用一个未使用的属性来输入我想要的回调变量。 所以在这种情况下,我有一个包含程序的文件夹,将制作按钮,并将 $Button.Text(其名称)设置为 .exe 的名称,然后将 $Button.Tag 设置为文件路径,所以当我执行 button.Add_Click 时,我只需调用 Button.Tag 因为它将具有我的 Exe 的路径。

    Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName PresentationFramework
[System.Windows.Forms.Application]::EnableVisualStyles()
$Form                            = New-Object system.Windows.Forms.Form
$Form.ClientSize                 = '580,400'
$Form.Text                       = "Test"
$Form.TopMost                    = $false
$Form.FormBorderStyle            = 'Fixed3D'
$Form.MaximizeBox                = $false
$Form.minimumSize                = New-Object System.Drawing.Size(580,400) 
$Form.maximumSize                = New-Object System.Drawing.Size(580,400) 

#Place Holder Form Junk Above




#Reset these on Run
$Global:x             = 10 #Reset up down
$Global:z             = 10 #Reset left right
$Global:ObjectNumber = -1 #Reset Object Count






Function Make-Button([string] $ToolName, [string] $ToolPath, [string] $SetZ, [string] $SetX){
$Button                         = New-Object system.Windows.Forms.Button
$Button.text                    = $ToolName
$Button.width                   = 120
$Button.height                  = 120
$Button.location                = New-Object System.Drawing.Point($SetZ,$SetX)
$Button.Font                    = New-Object System.Drawing.Font('Franklin Gothic',10)
$Button.FlatStyle           = [System.Windows.Forms.FlatStyle]::Flat
$Button.FlatAppearance.BorderSize  = 0
$Button.ForeColor           = [System.Drawing.ColorTranslator]::FromHtml("#ffffff")
$Button.BackColor           = [System.Drawing.ColorTranslator]::FromHtml("#515582")

$Button.tag = $ToolPath #<- this is where the answer was. Throwing my desired callback into an unused property of the the Button. in this case, i used _.Tag
$Button.Add_Click{start $this.tag}

$Form.Controls.AddRange(@($Button))

Write-Host "$ToolName"
Write-Host "$ToolPath"
Write-Host "$SetZ"
Write-Host "$SetX"

}

function Get-Position{
switch ($Global:ObjectNumber) {
-1{$Global:ObjectNumber += 1
Write-Host "Object:" $Global:ObjectNumber 

$Global:x = 0
$Global:z += 0}


Default{$Global:ObjectNumber += 1
Write-Host "Object:" $Global:ObjectNumber 

$Global:x += 0
$Global:z += 140}
}#end switch

if($Global:z -eq 570){ #Make New Row
$Global:x += 140
$Global:z = 10
Write-Host "New Row"
}
}


$Tools = Get-ChildItem "C:\WINDOWS\system32" -Filter *.exe
$Count = ( $Tools | Measure-Object ).Count;
Write-Host "Entries:" $Count





$Names = @($Tools) #Put Tools in Array
$Names | ForEach-Object{

                        Get-Position
                        Make-Button ($_.Name).replace(".exe","") ($_.FullName) ($z) ($x)

}











#End Form
$Test.Add_Shown(            {$Test.Activate()})
$Test.ShowDialog() 
[void]$Form.ShowDialog()

【讨论】:

  • @postanote 我找到了一种方法来做到这一点。如果您想看看上面发布的代码
猜你喜欢
  • 1970-01-01
  • 2019-08-21
  • 2011-12-12
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2017-01-23
相关资源
最近更新 更多