Powershell GUI - Elemente einer Listbox weiter verwenden?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

In Powershell lässt sich so wunderbar mit Objekten arbeiten. Man kann was hinzufügen oder entfernen oder sich nur auf eine Teil des Objekts beziehen.. oder gar etwas völlig neues kreieren.

Du brauchst lediglich zu Deinen mit Get-Childitem eingelesenen und mit Select ausgewählten Properties ein Neue hinzufügen (den KurzNamen /MaschinNummer oder Whatever)

Damit hältst Du alle Daten in einer intexierbaren Liste/Array zusammen. danach brauchst Du dich nicht mehr um den Zusemenhang zu kümmern du sprichst lediglich die Elemente über den Index der gewählten Objekte an.

Deiner Listbox übergibst du nur das, was man sehen soll. Welche Daten da sonst noch dranhängen ist unwichtig, wenn Du was auswählst, kennt die Listbox die Inidizes (Indexe) ...und die ButtonAktion nimmt sich diese Nummern und macht was mit der Liste.

(falls jemandem aufstößt, das ich besser mit Bindings hätte arbeiten können... Ich wollte der Einfachheit halber bewusst nicht noch eine Schicht reinbringen . Darum knallharte Direktzugriffe)

using namespace System.Windows.Forms
Add-Type -a System.Windows.Forms , System.Drawing

  #Rohdaten ... mit Arraylist  lässt  sich  gezielter  arbeiten als mit PowershellArrays
[System.Collections.ArrayList]$TableData = @(Get-ChildItem $env:Temp -file)|
    Select-Object  Name,Directory,Fullname|
    Foreach-Object {
        $_MyShortString = (($_.FullName -split '\\')|select -last 2) -join '\'
        $_|Add-Member -NotePropertyName Shorty -NotePropertyValue $_MyShortString   #neue Property und deren wert  hizufügen
        $_
    }
$TableData|ft  #nur  mal  etwas Datengucken

$Form = New-Object Form
$Form.Size = '900,300'
$ListBox = New-Object ListBox 
$ListBox.Size = '700,200'
$ListBox.Location = '10,30'
$ListBox.DataSource = $TableData.Shorty;  #wir schmeißen einfach knallhart ale Shortys rein (powershell regelt  das schon ;p )
$ListBox.SelectionMode = 'MultiExtended'
$Form.Controls.Add($ListBox)

$Button1 = New-Object Button
$Button1.Size = '150,25'
$Button1.Location = '720,30'
$Button1.Text = 'Show Path in Console'
$Button1_Action = {
    $ListBox.SelectedIndices|
      Sort-Object -Descending|   #...mit  höchstem Index  beginnen... (hier nicht zwingend  nötig)
      Where-Object {
        Write-Host $_
        Write-Host $TableData[$_].Shorty -fo Red     #der Index zeigt auf die Arrayelemente der DatenQuelle.
        Write-Host $TableData[$_].FullName -fo Magenta
      }
}
$Button1.Add_Click($Button1_Action)
$Form.Controls.Add($Button1)

$Button2 = New-Object Button
$Button2.Size = '150,25'
$Button2.Location = '720,60'
$Button2.Text = 'remove  selected'
$Button2_Action = {
    $ListBox.SelectedIndices|
      Sort-Object -Descending|   # wichtig!!! hier ist  es  wirklich nötig Array/List -Aktionen von oben zu beginnen,  da  sich  sonst der Index innerhalb des Ziels bei jeder Einzelaktion verändert
      Where-Object {
        Write-Host $_
          #hier was mit den durch die Daten in der Quelle[Index]  represntierten Objekten passiern soll
          #das  kannst  Du im prinzip auch  als Job erledigen
          #wichtig , das  muss passieren bevor  Du den Eintrag  entfenst in der Datenquelle  entfernst!!!!
        Write-Host ('Tue so als  würde ich die Datei: "{0}" im Ordner {1} loeschen' -f $TableData[$_].Name,$TableData[$_].Directory) -fo red

        $TableData.RemoveAt($_)     # Eintrag aus  der Liste entfernen der Index zeigt auf die Arrayelemente der DatenQuelle.
      }
      #das folgende hat  nichs  mit Get_Item  oder anderen Physischne Datenquellen  zu tun , sondern  bezieht sich lediglich  auf die zu Anfang erstellte  Liste/Array
      #..mit geänderter Datenquelle  sychronisieren
    $ListBox.DataSource = $TableData.Shorty;
}
$Button2.Add_Click($Button2_Action)
$Form.Controls.Add($Button2)

$Form.ShowDialog()

Write-Host  So  sieht unsere Arraylist  am ende  aus: -fo Blue
sleep 2
$TableData|ft

pause

etwa blöd kommt mir die Listbox trotzdem vor...

Forms hat auch eine wunderbare Tabelle, welche sich automatisch an die übergebenen Daten anpasst. DataGridView

Man kann sich die Spalten zurechtziehen, wie auch beim Explorer. Im folgenden habe ich die Selekttirbarkeit von Einzelzellen blockiert, weil wir das für Deine Ansprüche nicht benötigen.

using namespace System.Windows.Forms
Add-Type -a System.Windows.Forms , System.Drawing

  #DataGridView will kein  Normales Powershell [Array] !
[System.Collections.ArrayList]$TableData = @(Get-ChildItem $env:Temp -file)|
    Foreach-Object {
        $_MyShortString = (($_.FullName -split '\\')|select -last 2) -join '\'
        $_|Add-Member -NotePropertyName Shorty -NotePropertyValue $_MyShortString   #neue Property und deren wert  hizufügen
        $_
    }|
    Select-Object  Shorty,Name,Directory,FullName,Length,CreationTime,LastAccessTime,LastWriteTime  #was  Du  von den ganzen Korb an Properties in der Tabelle anzeigen willst
$TableData|ft

$Form = New-Object Form
$Form.Size = '900,300'

$DataGridView = New-Object DataGridView 
$DataGridView.Size = '700,200'
$DataGridView.Location = '10,30'
$DataGridView.DataSource = $TableData
$DataGridView.ColumnHeadersVisible = $true
$DataGridView.ReadOnly = $true
$dataGridView.SelectionMode = 'FullRowSelect'

$Form.Controls.Add($DataGridView)

$Button1 = New-Object Button
$Button1.Size = '150,25'
$Button1.Location = '720,30'
$Button1.Text = 'Show Path in Console'
$Button1_Action = {
    $Datagridview.SelectedRows|
      Sort-Object Index -Descending|   #Array-Aktionen möglichst immer  mit dem höchsten Index beginnen 
      Where-Object {
        Write-Host $_.Index
        Write-Host $Datagridview.DataSource[$_.Index].Name -fo Red     #der Index zeigt auf die Arrayelemente der DatenQuelle.
        Write-Host  $Datagridview.DataSource[$_.Index].Directory -fo Magenta
      }
}
$Button1.Add_Click($Button1_Action)
$Form.Controls.Add($Button1)

$Button2 = New-Object Button
$Button2.Size = '150,25'
$Button2.Location = '720,60'
$Button2.Text = 'remove  selected'
$Button2_Action = {
    $Datagridview.SelectedRows|
      Sort-Object Index -Descending|   # wichtig!!! hier ist  es  wirklich nötig Array/List -Aktionen von oben zu beginnen,  da  sich  sonst der Index innerhalb des Ziels bei jeder Einzelaktion verändert
      Where-Object {
        Write-Host selectet index: $_.Index
          #hier was mit den durch die Daten in der Quelle[Index]  represntierten Objekten passiern soll
          #das  kannst  Du im prinzip auch  als Job erledigen
          #wichtig , das  muss passieren bevor  Du den Eintrag  entfenst
        Write-Host ('Tue so als  würde ich die Datei: "{0}" im Ordner {1} loeschen' -f $Datagridview.DataSource[$_.Index].Name,$Datagridview.DataSource[$_.Index].Directory) -fo red
        Write-Host ('Neee: "{0}" ist  nich geloescht' -f $Datagridview.DataSource[$_.Index].FullName) -fo green
        $Datagridview.DataSource.RemoveAt($_.Index)     # Eintrag entfernen der Index zeigt auf die Arrayelemente der DatenQuelle.
      }
      #das folgende hat  nichs  mit Get_Item  oder anderen Physischne Datenquellen  zu tun , sondern  beziht   sich lediglich  auf die zu Anfang erstellte  Liste/Array
      #narrensichere Methode, da Datagridview sonst versuchen würde Nicht mehr  vorhandene Zellen  einzeln abzugrasen...
    $DataGridView.DataSource = $null; #...kurz von  der  Datenquelle lösen
    $DataGridView.Update();
    $DataGridView.DataSource = $TableData #Datenquelle wieder zuweisen
       
}
$Button2.Add_Click($Button2_Action)
$Form.Controls.Add($Button2)

$Form.ShowDialog()
Write-Host  So  sieht unsere Arraylist  am ende  aus: -fo Blue
sleep 2
$TableData|ft

pause
Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
DNSxxx 
Fragesteller
 13.05.2022, 20:40

Hallo "Erzesel".

Wie immer eine Antwort die mit beispielloser Detailgenauigkeit verfasst wurde.

Die meisten Menschen würden diese Zeit nicht mal für einen Freund opfern, und du tust das immer wieder um einem Fremden (würde gern einer sein) Programmierer auf die Sprünge zu helfen.

Zum Thema:

Version 1 deiner Antwort ist genau das wie ich es mir vorgestellt habe, aber bin am überlegen ob ich nicht deine zweite Version verwende, da man hier schön den letzten Zufgriff sieht.

Ich muss in der Arbeit mal erfragen ob es ihnen nicht zuviele Informationen sind.

Auf jeden Fall werd ich es jetzt mal Schritt für Schritt nachvollziehen damit ich es nicht nur kopiere sondern auch verstehe.

Vielen Vielen Dank für die Hilfe

Hochachtungsvoll

Gruß Thomas

0
Erzesel  14.05.2022, 02:42
@DNSxxx

DataGridView ist eines der mächtigsten Controls über das Forms verfügt. Ich habe aus Gründen der Übersichtlichkeit des Codes auf das Ausblenden von Spalten oder /und vorgabe von Spalrenbreiten und den Ganzen Kram verzichtet.

Ich dachte nur das es interessant sein könnte zu demonstrieren, wie einfach sich dieses Control an die gelieferten Daten anpasst. Wenn Du die Auswahl/ Reihenfolge der Properties von Select in Tabledata änderst, wirkt sich das automatisch auch auf die GridView aus.

Theoretisch kannst Du auch nicht anzuzeigende Daten in einem zweiten Array verwalten. Dann musst Du aber dafür sorgen, das diese synchron verwaltet werden... ( mache ich ja im prinzp schon bei der Listbox... Diese bekommt ja auch nur die "Shoortys" zu sehen. Obwohl da viel mehr Daten in den Objekten sind.)

Du kannst aber auch die Gridview statisch definieren und die Properties den Spalten zuweisen.

1