PowerShell Programmierung
Basics über das Programmieren in und mit Powershell
Sprache
Die Sprache ist das Fundament von PowerShell. Variablen, Operatoren, Strings und andere Sprachelemente bestimmen, was dein Code tut und warum er manchmal etwas völlig anderes tut als erwartet. Wenn du verstehen willst, wie PowerShell denkt, beginnt die Reise hier.
Escape-Sequenzen
Escape-Sequenzen sind spezielle Zeichenkombinationen, mit denen sich Steuerzeichen innerhalb von Strings darstellen lassen, z. B. Zeilenumbrüche oder Tabs.
In PowerShell wird dafür das Backtick-Zeichen verwendet:
`
Grundlagen
Escape-Sequenzen funktionieren nur in doppelt-quoted Strings:
"Text`nNeue Zeile" # funktioniert
'Text`nNeue Zeile' # kein Effekt
Wichtige Escape-Sequenzen
| Sequenz | Bedeutung | Beschreibung |
|---|---|---|
`n |
New Line | Zeilenumbruch |
`r |
Carriage Return | Cursor an den Anfang der Zeile |
`r`n |
Windows-Zeilenumbruch | Kombination aus CR + LF |
`t |
Tab | Tabulator |
| `` | Backtick | Gibt ein Backtick-Zeichen aus |
`" |
Anführungszeichen | Doppelte Quotes innerhalb von Strings |
Beispiele
Zeilenumbruch
"Hallo`nWelt"
Ausgabe:
Hallo
Welt
Tabulator
"Name`tAlter"
Ausgabe:
Name Alter
Windows-Zeilenumbruch
"Hallo`r`nWelt"
Verhalten in Dateien
Beim Arbeiten mit Dateien (z. B. Out-File, Set-Content) wird häufig `r`n verwendet, da dies dem Windows-Standard entspricht.
Typische Stolperfallen
1. Falsche Anführungszeichen
'Hallo`nWelt' # ❌ kein Umbruch
2. Backtick übersehen
Das Escape-Zeichen ist kein Apostroph ('), sondern:
`
3. Unsichtbare Zeichen
Escape-Sequenzen sind nicht sichtbar im Code, wirken aber auf die Ausgabe. Das macht Debugging manchmal… sagen wir… charakterbildend.
Alternative Methoden
.Split() (kein Escape, aber oft verwandt)
"text1,text2" -split ","
Oder:
"text1,text2".Split(",")
.Split() ist eine .NET String-Methode, kein Escape-Mechanismus, wird aber oft im gleichen Kontext verwendet, wenn Strings verarbeitet werden.
Fazit
Escape-Sequenzen sind ein einfacher Weg, um Strings zu formatieren, ohne sie über mehrere Zeilen schreiben zu müssen.
Das wichtigste:
-
Backtick = Escape
-
Nur in
" "aktiv -
`nfür schnellen Zeilenumbruch -
`r`nfür Windows-Kompatibilität
Enum-Werte
Enum-Werte bedeuten vordefinierte mögliche Werte
[System.Environment+SpecialFolder]
| Wert | Bedeutung |
Desktop |
Desktop – Der Desktop vom aktuellen Benutzer |
MyComputer |
Dieser PC – beinhaltet Datenträger und Laufwerke |
Programs |
Startmenü Programme – Im Startmenü angezeigten Programme |
MyDocuments
Personal
Favorites
Startup
Recent
SendTo
StartMenu
MyMusic
MyVideos
DesktopDirectory
NetworkShortcuts
Fonts
Templates
CommonStartMenu
CommonPrograms
CommonStartup
CommonDesktopDirectory
ApplicationData
PrinterShortcuts
LocalApplicationData
InternetCache
Cookies
History
CommonApplicationData
Windows
System
ProgramFiles
MyPictures
UserProfile
SystemX86
ProgramFilesX86
CommonProgramFiles
CommonProgramFilesX86
CommonTemplates
CommonDocuments
CommonAdminTools
AdminTools
CommonMusic
CommonPictures
CommonVideos
Resources
LocalizedResources
CommonOemLinks
CDBurning
PowerShell Variablen
Variablen die von PowerShell je nach Kontext, selbst deklariert werden.
| Variable | Beschreibung |
$PSCommandPath |
Vollständiger Pfad zum aktuellen Skript |
$PSModulePath |
Beinhaltet die Pfade zu den Modulen |
$PSScriptRoot |
Der Pfad zum Ordner worin sich das aktuelle Skript befindet |
$MyInvocation |
Enthält Infos darüber, wie das Skript aufgerufen wurde |
$PSScriptRoot
- Datentyp:
System.String
$PSCommandPath
- Datentyp:
System.String
$PSScriptRoot
- Datentyp:
$MyInvocation
- Datentyp:
InvocationInfo
Enthält Infos darüber, wie das Skript aufgerufen wurde
$MyInvocation.MyCommand– Informationen und die Idendität des aktuellen Kommando-Objekts-
$MyInvocation.MyCommand.CommandType$MyInvocation.MyCommand.Path– Enthält den Pfad zum aktuellen Skript
Operatoren
Operatoren sind spezielle Sprachelemente in PowerShell, die Werte verarbeiten, vergleichen, verknüpfen oder verändern. Sie bilden einen zentralen Bestandteil der Sprache und werden in nahezu jedem Skript verwendet.
Je nach Typ übernehmen Operatoren unterschiedliche Aufgaben:
-
Werte vergleichen (
-eq,-ne,-gt, ...) -
Logische Bedingungen verknüpfen (
-and,-or,-not) -
Inhalte zusammenführen oder aufteilen (
-join,-split) -
Berechnungen durchführen (
+,-,*,/)
String- und Array-Operatoren
Diese Operatoren werden häufig verwendet, um Texte und Listen zu verarbeiten.
Split
Der Operator -split zerlegt einen String anhand eines Trennzeichens in mehrere Elemente eines Arrays.
Beispiel:
"Max;Mustermann;30" -split ";"
Ergebnis:
Max
Mustermann
30
Weitere Informationen findest du auf der Seite Split.
Join
Der Operator -join führt mehrere Elemente eines Arrays zu einem einzelnen String zusammen.
Beispiel:
"Max","Mustermann",30 -join ";"
Ergebnis:
Max;Mustermann;30
Weitere Informationen findest du auf der Seite Join.
Merksatz
-split macht aus einem String ein Array.
-join macht aus einem Array einen String.
Beide Operatoren werden häufig gemeinsam verwendet, wenn Daten eingelesen, verarbeitet und anschließend wieder ausgegeben werden.
Join
Der -join Operator in PowerShell wird verwendet, um mehrere Elemente (z. B. Strings in einem Array) zu einem einzigen String zusammenzufügen.
🧠 Syntax
<array> -join <delimiter>
Oder ohne Trennzeichen:
<array> -join
📌 Grundlagen
-
Gibt immer einen String (
System.String) zurück -
Verbindet alle Elemente eines Arrays in der gegebenen Reihenfolge
-
Der Delimiter wird wörtlich verwendet (kein Regex!)
-
Standard-Delimiter ist ein leerer String (
"")
🔹 Beispiele
Einfaches Zusammenfügen
$array = "Apfel","Birne","Banane"
$result = $array -join ","
Ergebnis:
Apfel,Birne,Banane
Join ohne Trennzeichen
$array = "Hallo","Welt"
$result = $array -join
Ergebnis:
HalloWelt
Join mit Leerzeichen
$array = "Das","ist","ein","Test"
$result = $array -join " "
Ergebnis:
Das ist ein Test
Join mit Zeilenumbruch
$array = "Zeile1","Zeile2","Zeile3"
$result = $array -join "`n"
Ergebnis:
Zeile1
Zeile2
Zeile3
⚠️ Wichtige Hinweise
1. Kein Regex
Im Gegensatz zu -split:
Der Delimiter wird nicht als regulärer Ausdruck interpretiert.
Das bedeutet:
-
Sonderzeichen haben keine spezielle Bedeutung
-
"."ist einfach ein Punkt, kein Platzhalter
2. $null-Werte
$array = "A",$null,"B"
$result = $array -join ","
Ergebnis:
A,,B
Erklärung:
-
$nullwird als leerer String behandelt -
Der Delimiter wird trotzdem eingefügt
3. Nicht-String-Werte
$array = 1,2,3
$result = $array -join "-"
Ergebnis:
1-2-3
Erklärung:
-
Alle Elemente werden automatisch in Strings konvertiert
🔄 Alternative Methoden
[string]::Join()
[string]::Join(",", $array)
Unterschied zu -join:
-
Methodenaufruf statt Operator
-
Gleiche Funktionalität, oft in .NET-Kontexten verwendet
🧩 Typische Anwendungsfälle
-
Array in einen String umwandeln
-
CSV-Zeilen erzeugen
-
Textausgaben formatieren
-
Mehrzeilige Strings erzeugen
🧪 Mini-Beispiel aus der Praxis
$user = "Max","Mustermann",30
$csv = $user -join ";"
Ergebnis:
Max;Mustermann;30
🧠 Merksatz
-joinklebt alles zusammen. Ohne Struktur, wenn du keinen Delimiter setzt.
Split
Der -split Operator in PowerShell wird verwendet, um einen String anhand eines Trennzeichens (Delimiter) in ein Array von Teilstrings aufzuteilen.
🧠 Syntax
<string> -split <delimiter>
Oder mit erweiterten Optionen:
<string> -split <delimiter>, <max-substrings>, <options>
📌 Grundlagen
-
Gibt immer ein Array (
System.String[]) zurück -
Der Delimiter ist ein regulärer Ausdruck (RegEx!), kein einfacher Text
-
Groß-/Kleinschreibung kann beeinflusst werden
🔹 Beispiele
Einfaches Splitten
$text = "Apfel,Birne,Banane"
$result = $text -split ","
Ergebnis:
Apfel
Birne
Banane
Split mit Leerzeichen
$text = "Das ist ein Test"
$result = $text -split " "
Mehrere Trennzeichen (Regex)
$text = "Apfel;Birne,Banane"
$result = $text -split "[,;]"
Erklärung:
-
[ , ; ]bedeutet: splitte bei Komma oder Semikolon
💡 Verhalten bei max-substrings
Wenn die maximale Anzahl an Elementen erreicht ist:
Das letzte Element im Ergebnis enthält den gesamten verbleibenden Rest des Strings und wird nicht weiter gesplittet.
$text = "A,B,C,D"
$result = $text -split ",", 2
Ergebnis:
A
B,C,D
Erklärung:
-
Es werden maximal 2 Elemente erzeugt
-
Das erste Element entsteht durch den ersten Split
-
Das zweite Element enthält alles, was danach noch übrig ist (
B,C,D)
🧩Split mit Optionen
$text = "a,b,c"
$result = $text -split ",", 0, "IgnoreCase"
Mögliche Optionen:
-
IgnoreCase
→ Groß- und Kleinschreibung wird ignoriert
→"A,B,C" -split "a"würde trotzdem funktionieren -
CaseSensitive
→ Groß- und Kleinschreibung wird beachtet
→"A,B,C" -split "a"liefert kein Ergebnis, da kein Match -
SimpleMatch
→ Der Delimiter wird als normaler Text behandelt, nicht als Regex
→ Sonderzeichen wie.,*,+verlieren ihre Regex-BedeutungBeispiel:
"1.2.3" -split ".", 0, "SimpleMatch"→ funktioniert ohne Escape (
\.)
⚠️ Wichtige Hinweise
1. Regex-Falle
$text = "1.2.3"
$result = $text -split "."
Problem:. bedeutet im Regex „beliebiges Zeichen“
➡️ Ergebnis: komplett zerlegt
Lösung:
$result = $text -split "\."
🗑 2. Leere Elemente
"text,,text" -split ","
Ergebnis:
text
text
Erklärung:
-
Jeder Teilstring entsteht zwischen zwei Trennzeichen (Delimiter)
-
Wenn zwei Delimiter direkt aufeinander folgen (
,,), liegt dazwischen kein Inhalt -
PowerShell erzeugt dafür trotzdem ein Element im Array
Dieses Element ist ein leerer String (
""), keinnull
🔄 Alternative Methoden
.Split() (kein Regex!)
$text = "A,B,C"
$result = $text.Split(",")
Unterschied zu -split:
-
.Split()verwendet kein Regex -
oft schneller und einfacher
-
weniger flexibel
[regex]::Split()
[regex]::Split("A,B,C", ",")
➡️ Alternative mit explizitem Regex-Handling
🧩 Typische Anwendungsfälle
-
CSV-Daten zerlegen
-
Log-Dateien parsen
-
Benutzereingaben aufteilen
-
Pfade oder Listen verarbeiten
🧪 Mini-Beispiel aus der Praxis
$csv = "Max;Mustermann;30"
$name = $csv -split ";"
$vorname = $name[0]
$nachname = $name[1]
$alter = $name[2]
🧠 Merksatz
-splitdenkt in Regex. Wenn du das vergisst, bekommst du Chaos statt Struktur.
Befehle
Start-Sleep
Das Cmdlet Start-Sleep pausiert die Ausführung eines Skripts oder einer Befehlssequenz für eine definierte Zeitspanne.
Es wird häufig verwendet, um:
-
Wartezeiten einzubauen
-
Prozesse zu synchronisieren
-
Ressourcen zu schonen (z. B. bei Schleifen)
🔧 Syntax
Start-Sleep [-Seconds] <Double> [<CommonParameters>]
Start-Sleep -Milliseconds <Int32> [<CommonParameters>]
📌 Parameter
-Seconds
-
Typ:
Double -
Pflicht: Ja (wenn
-Millisecondsnicht verwendet wird) -
Gibt die Wartezeit in Sekunden an
-
Dezimalwerte sind erlaubt
Start-Sleep -Seconds 2.5
-Milliseconds
-
Typ:
Int32 -
Pflicht: Ja (wenn
-Secondsnicht verwendet wird) -
Gibt die Wartezeit in Millisekunden an
Start-Sleep -Milliseconds 500
⚠️ Hinweise zur Verwendung
-
-Secondsund-Millisecondsdürfen nicht gleichzeitig verwendet werden -
Während der Ausführung blockiert
Start-Sleepden aktuellen Thread vollständig -
Es erfolgt keine Hintergrundverarbeitung während der Pause
📊 Verhalten
| Eigenschaft | Beschreibung |
|---|---|
| Blockierend | Ja |
| Rückgabewert | Keiner |
| Thread-Verhalten | Aktueller Thread wird pausiert |
| Genauigkeit | Abhängig vom System-Timer |
🧪 Beispiele
Einfaches Warten
Write-Host "Start"
Start-Sleep -Seconds 2
Write-Host "Ende"
Verwendung in Schleifen
for ($i = 1; $i -le 5; $i++) {
Write-Host "Durchlauf $i"
Start-Sleep -Seconds 1
}
Kurze Pause in Millisekunden
Start-Sleep -Milliseconds 200
Dynamische Wartezeit
$delay = 1.5
Start-Sleep -Seconds $delay
⚙️ Typische Anwendungsfälle
-
Polling (z. B. auf Datei oder Prozess warten)
-
Debugging (Abläufe verlangsamen)
-
UI-Skripte (z. B. kurz warten, bis Controls geladen sind)
-
API-Rate-Limiting
❗ Alternativen / Ergänzungen
[System.Threading.Thread]::Sleep()
[System.Threading.Thread]::Sleep(1000)
Unterschiede:
-
Arbeitet nur mit Millisekunden
-
Weniger PowerShell-idiomatisch
-
Kein Support für
CommonParameters
Start-Sleep vs. Start-Job
| Szenario | Empfehlung |
|---|---|
| Einfaches Warten | Start-Sleep |
| Asynchrone Ausführung | Start-Job |
| UI-Responsiveness wichtig | Kein Start-Sleep |
🚫 Typische Fehler
1. Beide Parameter gleichzeitig verwenden
# ❌ Falsch
Start-Sleep -Seconds 1 -Milliseconds 500
2. UI einfrieren
# ❌ Problematisch in WinForms/WPF
Start-Sleep -Seconds 5
➡️ Blockiert die UI komplett
3. Zu kurze Wartezeiten erwarten hohe Präzision
Start-Sleep -Milliseconds 1
➡️ Systembedingt oft ungenau
🧠 Best Practices
-
Für UI-Anwendungen besser Timer verwenden statt
Start-Sleep -
In Schleifen immer bewusst einsetzen, um CPU-Last zu reduzieren
-
Wartezeiten so kurz wie möglich halten
-
Für präzise Zeitsteuerung ggf. andere Mechanismen nutzen
Wenn du das Ding in einer WinForms-App benutzt, dann frierst du dir halt elegant dein UI ein und wunderst dich danach, warum alles tot wirkt. Klassischer Anfänger-Move, aber immerhin ein lehrreicher.
Join-Path
Das Cmdlet Join-Path kombiniert mehrere Pfadsegmente zu einem gültigen Dateisystempfad.
Es wird verwendet, um:
-
Pfade plattformunabhängig zusammenzusetzen
-
manuelles Hantieren mit Trennzeichen (
\oder/) zu vermeiden -
Fehler durch doppelte oder fehlende Separatoren zu verhindern
🔧 Syntax
Join-Path [-Path] <String> [-ChildPath] <String> [[-AdditionalChildPath] <String[]>] [<CommonParameters>]
-Path
-
Typ:
String -
Pflicht: Ja
-
Basispfad (z. B. Verzeichnis)
-ChildPath
-
Typ:
String -
Pflicht: Ja
-
Pfadsegment, das an
-Pathangehängt wird
Join-Path -Path "C:\Temp" -ChildPath "Datei.txt"
-AdditionalChildPath
Verfügbar ab: PowerShell 6+
-
Typ:
String[] -
Pflicht: Nein
-
Weitere Pfadsegmente, die nacheinander angehängt werden
Join-Path -Path "C:\Temp" -ChildPath "Logs" -AdditionalChildPath "2026","April"
⚠️ Hinweise zur Verwendung
-
Trennzeichen werden automatisch korrekt gesetzt (kein manuelles
\nötig) -
Funktioniert providerübergreifend (z. B. Registry, Zertifikate)
-
Mehrere Segmente werden sauber zusammengeführt
-
Bestehende Trennzeichen im Input werden berücksichtigt (keine doppelten
\\)
📊 Verhalten
| Eigenschaft | Beschreibung |
|---|---|
| Plattformabhängigkeit | Berücksichtigt das jeweilige Dateisystem |
| Rückgabewert | String (zusammengesetzter Pfad) |
| Validierung | Keine Existenzprüfung des Pfades |
| Separator-Handling | Automatisch korrekt |
🧪 Beispiele
Einfaches Zusammenfügen
Join-Path -Path "C:\Temp" -ChildPath "Datei.txt"
Ergebnis: C:\Temp\Datei.txt
Mehrere Segmente
Join-Path -Path "C:\Temp" -ChildPath "Logs" -AdditionalChildPath "2026","April"
Ergebnis: C:\Temp\Logs\2026\April
Mit Variablen
$base = "C:\Temp"
$file = "report.txt"
Join-Path -Path $base -ChildPath $file
Ergebnis: C:\Temp\report.txt
Provider-unabhängig (z. B. Registry)
Join-Path -Path "HKCU:\Software" -ChildPath "Microsoft"
⚙️ Typische Anwendungsfälle
-
Dynamische Dateipfade erstellen
-
Arbeiten mit temporären Verzeichnissen
-
Plattformunabhängige Skripte schreiben
-
Zusammenbau von Registry-Pfaden
❗ Alternativen / Ergänzungen
String-Konkatenation
# ❌ Fehleranfällig
"C:\Temp\" + "Datei.txt"
-
Fehleranfällig bei fehlenden oder doppelten Trennzeichen
-
Nicht plattformunabhängig
[System.IO.Path]::Combine()
[System.IO.Path]::Combine("C:\Temp", "Datei.txt")
Unterschiede:
-
.NET-Methode, nicht PowerShell-spezifisch
-
Keine Provider-Unterstützung (nur Dateisystem)
-
Kein Support für
CommonParameters
🧠 Best Practices
-
Immer
Join-Pathstatt String-Konkatenation verwenden -
Ab PowerShell 6 kann für mehrere Segmente
-AdditionalChildPathverwendet werden. -
Kombination mit
Test-Pathfür Existenzprüfung -
Variablen statt Hardcoding verwenden
Wenn du Pfade immer noch per String zusammenklebst, dann sabotierst du dich halt selbst mit Ansage. Funktioniert kurz, bricht später, und dann suchst du den Fehler wie ein Detektiv ohne Kaffee. Nimm einfach Join-Path und erspar dir das Drama.
Set-Alias
Das Cmdlet Set-Alias erstellt oder verändert einen Alias für ein Cmdlet, eine Funktion oder einen Befehl.
Ein Alias ist dabei einfach ein alternativer Kurzname für einen bestehenden Command.
Es wird häufig verwendet, um:
-
häufig genutzte Befehle schneller aufzurufen
-
eigene Kurzbefehle zu definieren
-
bestehende Aliase umzubiegen oder anzupassen
-
Shell-Umgebungen individueller zu gestalten
🔧 Syntax
Set-Alias [-Name] <String> [-Value] <String>
[-Description <String>]
[-Option <ScopedItemOptions>]
[-PassThru]
[-Scope <String>]
[-Force]
[-WhatIf]
[-Confirm]
[<CommonParameters>]
📌 Parameter
-Name
-
Typ:
String -
Pflicht: Ja
-
Name des Alias
Set-Alias -Name ll -Value Get-ChildItem
-Value
-
Typ:
String -
Pflicht: Ja
-
Zielbefehl, auf den der Alias zeigen soll
Set-Alias -Name edit -Value notepad
-Description
-
Typ:
String -
Pflicht: Nein
-
Fügt dem Alias eine Beschreibung hinzu
Set-Alias -Name gs -Value Get-Service -Description "Listet Dienste auf"
-Option
-
Typ:
ScopedItemOptions -
Pflicht: Nein
-
Steuert das Verhalten des Alias
Mögliche Optionen:
| Option | Bedeutung |
|---|---|
None |
Keine besondere Einschränkung |
ReadOnly |
Alias kann nur mit -Force geändert werden |
Constant |
Alias kann gar nicht mehr geändert werden |
Private |
Nur im aktuellen Scope sichtbar |
Set-Alias -Name test -Value Get-Date -Option ReadOnly
-PassThru
-
Gibt das erstellte Alias-Objekt zurück
Set-Alias -Name now -Value Get-Date -PassThru
-Scope
-
Legt fest, in welchem Scope der Alias existiert
Beispiele:
| Scope | Bedeutung |
|---|---|
Local |
Nur aktueller Scope |
Global |
Überall verfügbar |
Script |
Nur innerhalb des Skripts |
Set-Alias -Name ll -Value Get-ChildItem -Scope Global
-Force
-
Erzwingt das Überschreiben von
ReadOnly-Aliases
Set-Alias -Name ls -Value Get-Process -Force
⚠️ Hinweise zur Verwendung
-
Aliase speichern keine Parameter
-
Ein Alias ersetzt nur den Befehlsnamen
-
Aliase gelten standardmäßig nur für die aktuelle Sitzung
-
Für dauerhafte Aliase muss man sie ins Profil (
$PROFILE) schreiben -
Constant-Aliases können nicht mehr entfernt werden
📊 Verhalten
| Eigenschaft | Beschreibung |
|---|---|
| Rückgabewert | Standardmäßig keiner |
| Überschreibbar | Ja, außer Constant |
| Persistenz | Nur aktuelle Sitzung |
| Unterstützt Funktionen | Ja |
| Unterstützt EXE-Dateien | Ja |
🧪 Beispiele
Einfachen Alias erstellen
Set-Alias -Name ll -Value Get-ChildItem
Jetzt funktioniert:
ll
Alias für Programme
Set-Alias -Name np -Value notepad
Bestehenden Alias überschreiben
Set-Alias -Name ls -Value Get-Process -Force
Jetzt startet ls plötzlich Prozesse statt Dateien aufzulisten.
Ein hervorragender Weg, sich selbst drei Stunden später maximal zu verwirren.
Alias dauerhaft speichern
Add-Content -Path $PROFILE -Value 'Set-Alias -Name ll -Value Get-ChildItem'
Alias anzeigen
Get-Alias ll
⚙️ Typische Anwendungsfälle
-
Eigene Kurzbefehle erstellen
-
Linux-ähnliche Befehle nachbauen
-
Lange Befehlsnamen abkürzen
-
Eigene Shell-Umgebungen konfigurieren
-
Schnellzugriffe für Skripte
❗ Alternativen / Ergänzungen
New-Alias
New-Alias -Name ll -Value Get-ChildItem
Unterschied zu Set-Alias:
| Cmdlet | Verhalten |
|---|---|
New-Alias |
Erstellt nur neue Aliase |
Set-Alias |
Erstellt oder überschreibt |
Funktionen statt Alias
function ll {
Get-ChildItem -Force
}
Vorteil:
-
Kann Parameter enthalten
-
Deutlich flexibler
-
Besser für komplexe Logik
🚫 Typische Fehler
1. Denken, dass Aliase Parameter speichern
# ❌ Funktioniert NICHT wie erwartet
Set-Alias -Name ll -Value "Get-ChildItem -Force"
Ein Alias verweist nur auf einen Commandnamen.
Nicht auf eine komplette Befehlszeile.
➡️ Dafür nutzt man Funktionen.
2. Alias nach Neustart weg
Set-Alias -Name test -Value Get-Date
Nach neuer PowerShell-Sitzung verschwunden.
➡️ Alias ins $PROFILE schreiben.
3. Wichtige Standard-Aliase überschreiben
Set-Alias -Name cd -Value Get-Date
Technisch möglich.
Psychologisch fragwürdig.
🧠 Best Practices
-
Nur sinnvolle Kurzformen verwenden
-
Standard-Aliase nicht leichtfertig überschreiben
-
Für komplexe Logik lieber Funktionen nutzen
-
Dauerhafte Aliase ins
$PROFILEauslagern -
In Skripten sparsam mit Aliases umgehen, damit der Code lesbar bleibt
Module
Irgendwann wird jedes Skript groß genug, um unübersichtlich zu werden. Module helfen dabei, Funktionen, Variablen und andere Bestandteile sinnvoll zu organisieren und wiederzuverwenden. Kurz gesagt: weniger Chaos, mehr Struktur. Meistens jedenfalls.
Modules.psm1 – Erweiterungen für das Skript, die zusätzliche Variablen , Funktionen oder Objekte beinhalten. Es kann nicht allein ausgeführt werden und muss von einem Skript oder Manifest importiert werden .
Es gibt auch → modulqualifizierter Aufruf
Manifest
Ein PowerShell-Manifest (.psd1) ist im Grunde nur eine Hashtable mit vordefinierten Keys. Es enthält die Metadaten und Konfiguration zu deinem Modul – also alles, was PowerShell über dein Modul wissen muss, ohne den eigentlichen Code auszuführen. Deshalb liegt es bewusst in einer eigenen Datei, getrennt vom Modul selbst.
🧱 Grundlegende Metadaten
Das ist die Identität deines Moduls. Ohne das bist du einfach nur irgendein Skript mit Existenzkrise.
RootModule– Hauptdatei (.psm1oder.dll)ModuleVersion– Version (z. B.1.0.0)GUID– Eindeutige IDAuthor– Ersteller/Entwickler des ModulsCompanyName– UnternehmenCopyrightDescription– Beschreibung des Moduls
🔗 Abhängigkeiten
Hier sagst du: „Ich funktioniere nicht alleine, ich brauche andere.“
RequiredModules
→ Externe Abhängigkeiten
→ Angabe über Modulnamen (PowerShell sucht es selbst)
→ Müssen im System vorhanden sein (installiert / auffindbar, z.B. über$PSModulePath)
→ Gehören nicht zu deinem ModulRequiredAssemblies– DLLsScriptsToProcess– Skripte, die beim Laden ausgeführt werdenModuleList– Nur die Meta-Information welche andere Module zugehörig sindNestedModules
→ Angabe über Dateien/Pfade (du sagst konkret, was geladen wird)
→ Interne Bausteine deines Moduls
→ Werden zusammen mit deinem Modul geladen
→ Gehören zu deinem Modul dazu
🚀 Export (was nach außen sichtbar ist)
Das ist der Teil, wo du entscheidest, was du der Welt zeigst. Oder versteckst.
FunctionsToExportCmdletsToExportVariablesToExportAliasesToExport
👉 Klassiker:'*' = alles exportieren
oder explizit = bessere Kontrolle
🧠 Kompatibilität & Anforderungen
Hier wird’s picky.
PowerShellVersionPowerShellHostNamePowerShellHostVersionDotNetFrameworkVersionCLRVersionProcessorArchitecture
📦 Private Daten (der geheime Keller)
Alles, was du selbst definierst.
PrivateData– Hashtable für eigene Infos
Beispiel:
PrivateData = @{
PSData = @{
Tags = @('UI','Forms')
ProjectUri = 'https://...'
}
}
🌐 PSData (wichtig für Gallery etc.)
Teil von PrivateData, aber so wichtig, dass es eigentlich sein eigenes Ding ist.
🧩 Sonstiges (der „Warum gibt’s das?“ Bereich)
Selten gebraucht, aber existiert halt:
FileListTypesToProcessFormatsToProcessCompatiblePSEditions(Desktop,Core)HelpInfoURI
🔧 Mini-Beispiel
Damit du nicht nur trockene Theorie hast:
@{
RootModule = 'MeinModul.psm1'
ModuleVersion = '1.0.0'
GUID = '12345678-abcd-1234-abcd-1234567890ab'
Author = 'Jonny'
Description = 'Mein erstes Modul'
FunctionsToExport = @('Get-Thing', 'Set-Thing')
PowerShellVersion = '5.1'
PrivateData = @{
PSData = @{
Tags = @('Example','Test')
}
}
}
Der eigentliche Punkt (den viele übersehen)
Du brauchst vielleicht 30% davon wirklich.
Der Rest ist:
- entweder für Publishing
- oder für Leute, die Kontrolle lieben (oder Angst haben)
Wenn du lokal entwickelst:
→ RootModule, ModuleVersion, FunctionsToExport
→ fertig, läuft.
Import (Modul laden)
Hier passiert das Offensichtliche, das trotzdem erstaunlich oft falsch gemacht wird: Du lädst dein Modul in die aktuelle Session.
Ohne Import bist du einfach nur jemand, der Code hortet.
🔧 Grundbefehl
Import-Module MeinModul
PowerShell sucht dein Modul automatisch in den bekannten Modulpfaden ($env:PSModulePath).
Wenn es da liegt: easy. Wenn nicht: dein Problem.
📁 Import über Pfad
Wenn dein Modul irgendwo rumliegt, wo PowerShell es nicht findet:
Import-Module "C:\MeinProjekt\MeinModul.psm1"
Oder direkt das Verzeichnis:
Import-Module "C:\MeinProjekt\MeinModul"
PowerShell nimmt dann automatisch das Manifest (.psd1) oder die Moduldatei (.psm1).
🔁 Erneutes Laden (Reload)
Du änderst Code, aber PowerShell hängt noch am alten Stand fest? Überraschung.
Import-Module MeinModul -Force
-Force lädt das Modul neu, auch wenn es schon geladen ist.
Pflicht beim Entwickeln, außer du stehst auf Selbstverwirrung.
🎯 Selektiver Import
Du musst nicht alles laden. Du kannst gezielt nur bestimmte Dinge importieren:
Import-Module MeinModul -Function Get-Thing
Oder mehrere:
Import-Module MeinModul -Function Get-Thing, Set-Thing
Funktioniert natürlich nur, wenn dein Manifest das auch erlaubt (FunctionsToExport).
🧠 Automatischer Import
Seit neueren PowerShell-Versionen gilt:
Wenn du eine Funktion aus einem Modul aufrufst, wird es automatisch importiert.
Get-Thing
→ PowerShell denkt sich: „Kenn ich nicht… ach warte, da gibt’s ein Modul“
Klingt smart. Ist es auch.
Bis es nicht mehr funktioniert und du nicht weißt warum.
🔍 Geladene Module anzeigen
Get-Module
Alle verfügbaren Module anzeigen:
Get-Module -ListAvailable
Wenn dein Modul hier nicht auftaucht, kannst du lange importieren. Wird nix.
🧹 Modul entfernen
Falls du es wieder loswerden willst:
Remove-Module MeinModul
Hilfreich beim Entwickeln, wenn du nicht mit -Force arbeiten willst.
⚠️ Bereits geladenes Modul
Wenn ein Modul bereits geladen ist und du erneut Import-Module aufrufst, passiert… nichts.
Import-Module MeinModul
PowerShell sagt sich: „Kenn ich schon“ und ignoriert dich stillschweigend.
Das bedeutet:
- Änderungen im Code werden nicht übernommen
- Du arbeitest weiter mit der alten Version
Wenn du sicherstellen willst, dass dein Modul wirklich neu geladen wird:
Import-Module MeinModul -Force
Alternativ kannst du es vorher entfernen:
Remove-Module MeinModul Import-Module MeinModul
Wichtig beim Entwickeln:
Wenn sich „irgendwas komisch anfühlt“, ist es erstaunlich oft genau das hier.
Du debugst dann nicht deinen Code.
Du debugst deine Vergangenheit.
Der eigentliche Punkt (den wieder alle ignorieren)
Import ist kein einmaliger Akt, sondern Teil deines Workflows.
- Entwicklung → ständig
-Force - Debugging → bewusst laden/entladen
- Produktion → einmal sauber laden und fertig
Wenn dein Modul sich beim Import komisch verhält, liegt es fast nie am Import.
Es liegt daran, was dein Modul beim Laden tut.
Und genau da trennt sich „läuft irgendwie“ von „ich hab verstanden, was ich da gebaut habe“.
System.Windows.Forms
Namespace: System.Windows.Forms
Mit System.Windows.Forms können Forms erstellt werden, die wie ein Windows-Fenster agieren. Um es nutzen zu können, muss das entsprechende Assembly eingebunden werden:
Add-Type -AssemblyName System.Windows.Forms
CheckBox
Namespace: System.Windows.Forms
Eigenschaften / Propertys
-
Property – Standardwert
Beschreibung oder Erläuterung der Eigenschaft
-
Appearance – Normal
Darstellung der CheckBoxNormal= klassische CheckboxButton= verhält sich wie ein Toggle-Button -
AutoCheck – $true
Ob die CheckBox ihren Zustand automatisch selbst ändert -
Checked – $false
Ob die CheckBox aktiviert ist -
CheckState – Unchecked
Zustand der CheckBox
(Unchecked,Checked,Indeterminate) -
ThreeState – $false
Erlaubt dritten Zustand (Indeterminate) -
Text – ""
Angezeigter Text neben der Checkbox -
TextAlign – MiddleLeft
Ausrichtung des Textes -
CheckAlign – MiddleLeft
Position des Häkchens -
FlatStyle – Standard
Darstellung der Checkbox
(Standard,Flat,Popup,System) -
AutoSize – $false
Passt Größe automatisch an Inhalt an -
Enabled – $true
Aktiviert oder deaktiviert die CheckBox -
Visible – $true
Sichtbarkeit der CheckBox -
Font – Standard-Systemfont
Schriftart des Textes -
ForeColor – ControlText
Textfarbe -
BackColor – Transparent
Hintergrundfarbe -
Dock – None
Docking innerhalb des Containers -
Anchor – (Top, Left)
Verhalten bei Größenänderung des Containers -
Location – (0,0)
Position innerhalb des Containers -
Size – (104,24 ungefähr)
Größe der CheckBox -
TabIndex – 0
Reihenfolge beim Durchtabben -
TabStop – $true
Ob die CheckBox per TAB erreichbar ist
Die CheckBox gehört zu diesen Controls, die harmlos aussehen… bis man plötzlich merkt, dass daran halbe UI-Logik hängt.
Denn technisch gesehen ist sie nicht einfach nur „an oder aus“.
Sie ist oft ein kleiner Schalter für:
-
Einstellungen
-
Features
-
Berechtigungen
-
Optionen
-
Dynamisches UI-Verhalten
Und plötzlich hängt daran alles. Willkommen im Club menschlicher Selbstüberschätzung.
# CheckBox erstellen
$checkBox = New-Object System.Windows.Forms.CheckBox
$checkBoxNew = [System.Windows.Forms.CheckBox]::new()
# Text
$checkBox.Text = "Dark Mode aktivieren"
# Position & Größe
$checkBox.Location = New-Object System.Drawing.Point(10,10)
$checkBox.AutoSize = $true
# Standardmäßig aktiv
$checkBox.Checked = $true
📥 Werte auslesen
# Aktiviert?
$state = $checkBox.Checked
# Exakter Zustand
$checkState = $checkBox.CheckState
-
Event – Hinweistext
Auslöser / Trigger dieses Events
-
CheckedChanged
Wird ausgelöst, sobald sichCheckedändert -
CheckStateChanged
Feuert bei Änderung vonCheckState
-
Click
Wird bei jedem Klick ausgelöst -
DoubleClick
Feuert beim Doppelklick -
MouseDown
Feuert vorClick -
MouseUp
Feuert nachClick
-
KeyDown
Taste wird gedrückt -
KeyUp
Taste wird losgelassen
Events - CheckBox
✅ CheckedChanged
Das wichtigste Event der ganzen CheckBox.
Wird ausgelöst, sobald sich der Zustand ändert.
$checkBox.Add_CheckedChanged({
Write-Host "CheckBox Zustand:" $checkBox.Checked
})
👉 Das ist normalerweise das Event, das du wirklich willst.
Nicht Click.
Nicht MouseDown.
Nicht irgendwelche kreativen Konstruktionen aus emotionalem Kontrollverlust.
🔁 CheckStateChanged
Ähnlich wie CheckedChanged, aber für CheckState.
Relevant bei ThreeState.
$checkBox.ThreeState = $true
$checkBox.Add_CheckStateChanged({
Write-Host "State:" $checkBox.CheckState
})
👉 Ohne ThreeState bringt dir das meistens exakt gar nichts.
🖱️ Click
Feuert bei jedem Klick auf die CheckBox.
$checkBox.Add_Click({
Write-Host "CheckBox wurde geklickt"
})
Das Problem:
Click bedeutet nicht automatisch, dass sich der Zustand geändert hat.
Das vergessen Leute ständig und bauen dadurch doppelte Logik.
⌨️ KeyDown
Für Tastatursteuerung.
$checkBox.Add_KeyDown({
Write-Host $_.KeyCode
})
👉 Viele vergessen komplett, dass Benutzer auch Tastaturen besitzen. Faszinierende gesellschaftliche Entwicklung eigentlich.
🧩 ThreeState
Normalerweise kennt eine CheckBox nur:
Checked
Unchecked
Mit ThreeState kommt hinzu:
Indeterminate
Beispiel:
$checkBox.ThreeState = $true
$checkBox.CheckState = "Indeterminate"
Das nutzt man oft für:
-
Teilweise ausgewählt
-
Gemischte Zustände
-
„Nicht eindeutig“
Klassisches Beispiel:
Ordner-Auswahl mit Unterelementen
Einige aktiviert → graues Kästchen
🎨 Appearance = Button
Das hier kennen überraschend viele nicht:
$checkBox.Appearance = "Button"
Dann wird aus der CheckBox ein Toggle-Button.
$checkBox.Text = "Musik aktivieren"
$checkBox.Appearance = "Button"
👉 Sehr praktisch für moderne UI-Schalter.
Und ja, technisch bleibt es trotzdem einfach nur eine CheckBox im Kostüm. Menschen machen das übrigens auch ständig.
⚠️ Typische Stolperfallen
-
CheckedChangedfeuert auch bei Änderungen per Code
$checkBox.Checked = $true
→ Event wird trotzdem ausgelöst
-
ClickundCheckedChangedgleichzeitig nutzen
→ doppelte Ausführung
-
ThreeStateaktiviert, aber nurCheckedgeprüft
if ($checkBox.Checked)
→ ignoriert Indeterminate
-
AutoCheck = $false
Dann ändert die CheckBox ihren Zustand nicht selbst.
$checkBox.AutoCheck = $false
👉 Ab da bist du verantwortlich.
Glückwunsch. Du bist offiziell der Zustand-Manager deines kleinen Universums.
🧩 Best Practice
-
Für einfache Optionen →
CheckBox -
Für Ein/Aus-Schalter →
Appearance = Button -
Für mehrere zusammenhängende Optionen →
GroupBox -
Für „eine von vielen“ → eher
RadioButton
Ich greif einen Punkt raus, den viele komplett unterschätzen:
Eine CheckBox ist kein Datenspeicher. Sie ist nur UI.
Das hier:
if ($checkBox.Checked)
…ist kein „Systemzustand“.
Das ist nur die aktuelle Anzeige im Interface.
Wenn deine komplette Logik davon abhängt, ob irgendein Kästchen gerade angehakt ist, endet dein Projekt irgendwann wie ein Keller voller Verlängerungskabel. Funktioniert irgendwie. Bis jemand dagegen tritt.
CheckedListBox
Namespace: System.Windows.Forms
Properties / Eigenschaften
- Property – Standardwert
Beschreibung oder Erläuterung der Eigenschaft
Verhalten (Behavior)
- AllowDrop – $false
Drag & Drop erlauben - CheckOnClick – $false
Checkbox wird direkt beim Klick geändert (ohne zweiten Klick) - Enabled – $true
Aktiv / deaktiviert - FormattingEnabled – $true
Für komplexe Objekte - SelectionMode – One
Auswahlmodus (meist irrelevant hier) - Sorted – $false
Automatisch sortieren - ThreeDCheckBoxes – $false
3D-Darstellung der Checkboxen - ScrollAlwaysVisible – $false
Scrollbar immer anzeigen - HorizontalScrollbar – $false
Horizontale Scrollbar - TabStop – $true
Fokus per Tab
Daten / Inhalt (Data)
- Items – (leer)
Alle Einträge - CheckedItems – (leer)
Alle aktiv angehakten Items - CheckedIndices – (leer)
Indizes der angehakten Items - SelectedItem – $null
Aktuell markiertes Item (nicht gleich checked!) - TabIndex – 0
Tab-Reihenfolge
Layout & Position
- Location – (0,0)
Position - Size – (Width=120, Height=96)
- Width – (abhängig vom Layout)
- Height – (abhängig vom Layout)
- Anchor – (Top, Left)
Verhalten bei Größenänderung - Dock – None
Layout im Container - ItemHeight – (abhängig von Font)
Aussehen (Appearance)
- BackColor – SystemColors.Window
Hintergrundfarbe - ForeColor – SystemColors.WindowText
Textfarbe - Font – Standard-Systemfont
Schriftart - BorderStyle – Fixed3D
Rahmenstil (None,FixedSingle,Fixed3D) - Visible – $true
Sichtbarkeit
Meta / System
- Name – ""
Interner Name - TopIndex – 0
Oberstes sichtbares Item
Größe
Die CheckedListBox ist im Grunde eine ListBox mit eingebauten Checkboxen.
CheckedListBox erstellen
$clb = New-Object System.Windows.Forms.CheckedListBox
$clbNew = [System.Windows.Forms.CheckedListBox]::new()
Items hinzufügen
$clb.Items.Add("Apfel")
$clb.Items.Add("Banane")
$clb.Items.AddRange(@("Orange","Mango","Traube"))
📥 Werte auslesen
# Alle angehakten Items
$checked = $clb.CheckedItems
# Indizes
$indices = $clb.CheckedIndices
# Einzelnes Item (nur Fokus, nicht Check!)
$selected = $clb.SelectedItem
👉 Wichtiger Unterschied:SelectedItem ≠ CheckedItems
SelectedItembetrifft nur das Item, welches Ausgewählt ist.CheckedItemsbeinhaltet alle Items welches auch einen Haken haben
Events - CheckedListBox
Events
- Event
Wird ausgelöst, ...
- TextChanged
... wenn sich die Text-Eigenschaft des Controls ändert
Interaktion
-
Click
... wenn ein Eintrag der Liste angeklickt wird -
DoubleClick
... wenn ein Eintrag doppelt angeklickt wird - ItemCheck
... wenn sich der Checked-Zustand eines Items ändert (bevor die Änderung übernommen wird) - SelectedIndexChanged
... wenn sich die Auswahl (markiertes Item) ändert
Maus
-
MouseEnter
... wenn der Mauszeiger die CheckedListBox betritt -
MouseLeave
... wenn der Mauszeiger die CheckedListBox verlässt -
MouseMove
... wenn der Mauszeiger innerhalb der CheckedListBox bewegt wird -
MouseDown
... wenn eine Maustaste auf der CheckedListBox gedrückt wird -
MouseUp
... wenn eine Maustaste auf der CheckedListBox losgelassen wird -
MouseHover
... wenn der Mauszeiger für kurze Zeit auf der CheckedListBox verweilt
Tastatur
- KeyDown
... wenn eine Taste gedrückt wird, während die CheckedListBox den Fokus hat - KeyUp
... wenn eine gedrückte Taste wieder losgelassen wird - KeyPress
... wenn eine Taste gedrückt wird, die ein Zeichen erzeugt (z. B. Buchstaben, Zahlen)
Fokus
- Enter
... wenn das Control Fokus erhält - Leave
... wenn das Control Fokus verliert
Darstellung / Layout
-
Paint
... wenn die CheckedLisBox neu gezeichnet wird - LocationChanged
... wenn sich die Position der CheckedListBox ändert - SizeChanged
... wenn sich die Größe der CheckedListBox ändert
Zustand
-
EnabledChanged
... wenn sich der Enabled-Status der CheckedListBox ändert -
VisibleChanged
... wenn sich die Sichtbarkeit der CheckedListBox ändert
Aussehen
-
FontChanged
... wenn sich die Schriftart der CheckedListBox ändert -
ForeColorChanged
... wenn sich die Textfarbe der CheckedListBox ändert -
BackColorChanged
... wenn sich die Hintergrundfarbe der CheckedListBox ändert
Datenbindung
- DataSourceChanged
... wenn sich die Datenquelle ändert - DisplayMemberChanged
... wenn sich die Anzeigebindung ändert - ValueMemberChanged
... wenn sich die Wertbindung ändert
$sender
→ Das Objekt, das das Event ausgelöst hat. Meistens die CheckedListBox selbst
$e
→ Zusatzinfos zum Event → was genau ist passiert
$CheckedListBox.Add_Click({
param($sender, $e)
$sender.BackColor = "Red"
})
ItemCheck
$CheckedListBox.Add_ItemCheck({
param($sender, $e)
$e.Index
$e.NewValue
$e.CurrentValue
})
$e.Index→ welches Item$e.NewValue→ neuer Zustand$e.CurrentValue→ alter Zustand
Tipps & Tricks - CheckedListBox
Check direkt beim Klick
$checkListBox.CheckOnClick = $true
Alle gesetzten Werte holen
$clb.CheckedItems | ForEach-Object {
$_
}
🧩 Check programmatisch setzen
$clb.SetItemChecked(0, $true)
⚠️ Typische Stolperfallen
SelectedItembenutzt stattCheckedItemsItemCheckfalsch verstanden (Timing!)- Doppel-Events durch Click + ItemCheck
CheckOnClick = $false→ wirkt wie Bug
🧩 Mentales Modell
Die CheckedListBox hat zwei Zustände gleichzeitig:
- Fokus (SelectedItem)
- Check-Zustand (CheckedItems)
Wenn du das vermischst → Chaos.
🧩 Best Practice
- Für mehrere unabhängige Optionen → perfekt
- Für „eine Auswahl“ → falsches Control
- Für komplexe Daten → lieber eigene UI bauen
DialogResult
Überblick
System.Windows.Forms.DialogResult ist ein Enum, das den Rückgabewert eines Dialogfensters beschreibt. Es gibt an, wie ein Dialog geschlossen wurde, zum Beispiel durch Klick auf OK, Cancel, Yes oder No.
Der Typ wird hauptsächlich in Verbindung mit Windows-Forms-Dialogen wie MessageBox oder OpenFileDialog verwendet.
Typ
Enum (feste, benannte Werte; intern numerisch)
Werte (Auszug)
| Wert | Bedeutung |
None |
Kein Ergebnis oder Dialog noch nicht geschlossen |
OK |
OK-Schaltfläche gedrückt |
Cancel |
Abbrechen gedrückt oder Fenster geschlossen |
Yes |
Ja gedrückt |
No |
Nein gedrückt |
Abort |
Abbruch |
Retry |
Wiederholen |
Ignore |
Ignorieren |
Nicht jeder Dialog liefert jeden Wert zurück.
Die verfügbaren Rückgabewerte hängen von den verwendeten Buttons ab.
Verwendung:
- Vergleich von Dialog-Ergebnissen, z.B. MessageBox.Show()
- Typsichere Alternative zu String-Vergleichen
FolderBrowserDialog
Öffnet einen Dialog zur Auswahl eines Ordners.
Typischer Windows-"Ordner auswählen"-Dialog. Weil Menschen offenbar selbst beim Auswählen eines Verzeichnisses noch eine GUI brauchen und nicht einfach "C:\Irgendwas" eintippen können.
Konstruktor
$dialog = [System.Windows.Forms.FolderBrowserDialog]::new()
Eigenschaften
Description
Text oberhalb des Verzeichnisbaums.
$dialog.Description = "Wähle einen Zielordner aus"
SelectedPath
Der aktuell ausgewählte Ordnerpfad.
Kann:
-
vor dem Öffnen gesetzt werden → Startordner
-
nach dem Schließen ausgelesen werden → ausgewählter Ordner
$dialog.SelectedPath = "C:\Temp"
$dialog.SelectedPath
RootFolder
Legt fest, ab welchem Systemordner der Benutzer navigieren darf.
Verwendet Werte aus:
[System.Environment+SpecialFolder]
Beispiele:
-
Desktop -
MyComputer -
MyDocuments -
ProgramFiles
$dialog.RootFolder = [System.Environment+SpecialFolder]::Desktop
ShowNewFolderButton
Bestimmt, ob die Schaltfläche "Neuen Ordner erstellen" angezeigt wird.
$dialog.ShowNewFolderButton = $true
Methoden
ShowDialog()
Öffnet den Dialog.
Rückgabewert:
[System.Windows.Forms.DialogResult]
Meist:
-
OK -
Cancel
$result = $dialog.ShowDialog()
Dispose()
Gibt verwendete Ressourcen frei.
Technisch nicht immer zwingend nötig, aber sauberer. Besonders wenn man viele Dialoge erzeugt. Windows Forms sammelt sonst gerne kleinen Müll an wie ein Messie mit Kabelschublade.
$dialog.Dispose()
Einfaches Beispiel
Add-Type -AssemblyName System.Windows.Forms
$dialog = [System.Windows.Forms.FolderBrowserDialog]::new()
$dialog.Description = "Wähle einen Ordner"
$dialog.SelectedPath = "$env:USERPROFILE\Desktop"
$dialog.ShowNewFolderButton = $true
if ($dialog.ShowDialog() -eq "OK") {
$dialog.SelectedPath
}
$dialog.Dispose()
Typischer Ablauf
Dialog erstellen
↓
Eigenschaften setzen
↓
ShowDialog()
↓
DialogResult prüfen
↓
SelectedPath verwenden
↓
Dispose()
Wichtige Hinweise
SelectedPath setzt auch den Startordner
Viele denken:
"
RootFolderbestimmt den Startordner"
Nein.RootFolder begrenzt nur den sichtbaren Bereich.
Der tatsächliche Startordner kommt meistens von:
SelectedPath
Benutzer kann abbrechen
Darum niemals direkt:
$dialog.SelectedPath
verwenden ohne vorher:
ShowDialog()
zu prüfen.
Sonst arbeitest du eventuell mit leerem Inhalt weiter. Und plötzlich löscht ein Skript rekursiv "\". Kleine Eskalation. Riesige Wirkung.
Unterschied zu OpenFileDialog
| Dialog | Zweck |
|---|---|
FolderBrowserDialog |
Ordner auswählen |
OpenFileDialog |
Datei auswählen |
SaveFileDialog |
Speicherort + Dateiname auswählen |
Typische Verwendung
-
Installationspfad wählen
-
Backup-Ordner wählen
-
Exportpfad wählen
-
Scan-Verzeichnis wählen
-
Musik-/Bildordner auswählen
-
Benutzerfreundliche Pfadauswahl in GUIs
Minimalbeispiel
if ($dialog.ShowDialog() -eq "OK") {
$path = $dialog.SelectedPath
}
Das ist im Grunde der Kern von allem hier. Der Rest ist Komfort, Einschränkung oder kosmetische Kontrolle über das Windows-Chaos von 2003.
Form
Namespace: System.Windows.Forms
Properties / Eigenschaften
- Property – Standardwert
Beschreibung oder Erläuterung der Eigenschaft
-
AutoScaleMode – Font
Skalierung basierend auf Schriftgröße -
AutoSize – $false
Passt die Form automatisch an den Inhalt an -
BackColor – Control
Hintergrundfarbe -
ClientSize – (300,300)
Innenbereich der Form (ohne Rahmen) -
ControlBox – $true
Zeigt Schließen / Minimieren / Maximieren -
ForeColor – ControlText
Standard-Textfarbe -
FormBorderStyle – Sizable
Fensterrahmen (None,FixedSingle,Sizable, …) -
Icon – $null
Fenster-Icon ([Icon]::new("App.ico")) -
KeyPreview – $false
Form bekommt Key-Events vor Controls -
MaximizeBox – $true
Maximieren erlauben -
MaximumSize – (0,0)
Maximalgröße (0 = unbegrenzt) -
MinimumSize – (0,0)
Minimale Größe -
Opacity – 1.0
Transparenz (0.0 – 1.0) -
Padding – (0)
Innenabstand -
StartPosition – WindowsDefaultLocation
Startposition des Fensters -
ShowIcon – $true
Icon anzeigen -
ShowInTaskbar – $true
In Taskleiste sichtbar -
Size – (300,300)
Fenstergröße -
Text – ""
Fenstertitel -
TopMost – $false
Immer im Vordergrund -
WindowState – Normal
(Normal,Minimized,Maximized)
Eigenschaften, die sich gegenseitig beeinflussen
-
AutoSize = $true→ ignoriert Size -
Dock = "Fill"→ ignoriert AutoSize -
Dock = "Top"/"Bottom"→ Width wird ignoriert -
Dock = "Left"/"Right"→ Height wird ignoriert -
FormBorderStyle = "None"→ keine ControlBox, kein Icon sichtbar
Eine Form ist das Hauptfenster deiner Anwendung.
Sie ist der Container für alle anderen Controls.
Grundidee
Die Form ist die Bühne.
- enthält alle Controls
- verwaltet Layout und Lebenszyklus
- steuert Anzeige (
Show/ShowDialog)
Typischer Ablauf
- Properties setzen
- Controls hinzufügen
- Events definieren
- Form anzeigen (
Show()/ShowDialog())
Form erstellen
# Klassisch
$form = New-Object System.Windows.Forms.Form
# .NET-Style
$form = [System.Windows.Forms.Form]::new()
Form anzeigen
# Nicht blockierend
$form.Show()
# Modal (blockierend)
$form.ShowDialog()
Controls hinzufügen
$form.Controls.Add($button)
$form.Controls.AddRange(@($label, $textbox))
Layout & Verhalten
$form.Size = [System.Drawing.Size]::new(400, 300)
$form.StartPosition = "CenterScreen"
$form.TopMost = $true
$form.FormBorderStyle = "FixedDialog"
Events - Form
$form.Add_*
param($sender, $e)
-
$sender→ die Form selbst -
$e→ EventArgs
Load
Wird beim Initialisieren der Form ausgelöst
$form.Add_Load({
Write-Host "Form lädt"
})
Shown
Wird nach dem Anzeigen ausgelöst
$form.Add_Shown({
Write-Host "Form sichtbar"
})
FormClosing
Vor dem Schließen (kann verhindert werden)
$form.Add_FormClosing({
param($sender, $e)
$e.Cancel = $true # verhindert Schließen
})
FormClosed
Nach dem Schließen
$form.Add_FormClosed({
Write-Host "Form geschlossen"
})
Resize
Bei Größenänderung
$form.Add_Resize({
Write-Host "Neue Größe: $($this.Size)"
})
Tipps & Tricks - Form
Typische Stolperfallen
-
Form schließt sofort
→ keinShowDialog()verwendet -
Layout bricht auseinander
→Dock/Anchorfalsch gesetzt -
Größe ignoriert
→AutoSizeaktiv -
Fenster reagiert nicht auf Keys
→KeyPreview = $truefehlt
Mentales Modell
Die Form ist der Lebenszyklus-Controller deiner UI.
Sie bestimmt:
-
wann etwas sichtbar ist
-
wann etwas endet
-
wie alles organisiert ist
Wann sinnvoll?
-
Immer (jede WinForms-App braucht mindestens eine Form)
Wann problematisch?
-
Zu viel Logik direkt in der Form
-
Vermischung von UI und Business-Logik
Label
Ein Label ist ein reines Anzeige-Control für Text.
Es dient zur Beschreibung, Anzeige oder Strukturierung von UI-Inhalten.
Ein Label ist nicht für direkte Benutzerinteraktion vorgesehen, kann jedoch auf Ereignisse wie Mausklicks reagieren.
Label erstellen
# Klassisch
$label = New-Object System.Windows.Forms.Label
# .NET-Style
$label = [System.Windows.Forms.Label]::new()
Eigenschaften - Label
Eigenschaften
- Property – Standardwert
Beschreibung oder Erläuterung der Eigenschaft
-
Text – ""
Angezeigter Text -
AutoSize – $false
Passt Größe automatisch an den Inhalt an -
TextAlign – TopLeft
Ausrichtung des Textes innerhalb des Labels -
BorderStyle – None
Rahmenstil des Labels -
Dock – None
Layout innerhalb des Parent-Containers -
Anchor – (Top, Left)
Verhalten bei Größenänderung des Containers -
Padding – (0, 0, 0, 0)
Innenabstand -
Margin – (3, 3, 3, 3)
Außenabstand -
UseMnemonic – $true
Aktiviert Zugriff über Alt+Key (z.B. &Datei)
geerbt von Control
-
Width – 100
Breite des Labels -
Height – 23
Höhe des Labels -
Size – (Width=100, Height=23)
Größe des Labels -
Location – (0, 0)
Position innerhalb des Containers -
ForeColor – SystemColors.ControlText
Textfarbe (systemabhängig) -
BackColor – Transparent
Hintergrundfarbe (übernimmt Parent-Hintergrund) -
Font – Microsoft Sans Serif, 8.25pt
Standard-Systemschrift -
Enabled – $true
Aktiviert das Label -
Visible – $true
Sichtbarkeit des Labels -
TabIndex – 0
Reihenfolge beim Durchtabben -
TabStop – $false
Label ist standardmäßig nicht per Tab erreichbar -
Name – ""
Interner Name des Controls
Text
Typ: system.String
Die Eigenschaft Text legt den angezeigten Inhalt eines Labels fest.
$label.Text = "Hallo Welt"
# Mehrzeilig
$label.Text = "Zeile 1`nZeile 2"
PowerShell macht implizite Konvertierung:
$Label.Text = 123
funktioniert, weil es intern zu "123" wird.
AutoSize
Typ: System.Boolean
Die Eigenschaft AutoSize bestimmt, ob sich das Label automatisch an die Größe seines Inhalts anpasst.
# Automatische Größe
$label.AutoSize = $true
Size
Typ: System.Drawing.Size
# Feste Größe
$label.Size = [System.Drawing.Size]::new(200, 30)
TextAlign
Typ: System.Drawing.ContentAlignment
# Text zentrieren
$label.TextAlign = "MiddleCenter"
Events - Label
Events
- Even
Wird ausgelöst, ...
Interaktion (User Input)
-
Click
... wenn das Label mit der Maus angeklickt wird -
DoubleClick
... wenn das Label doppelt angeklickt wird -
MouseEnter
... wenn der Mauszeiger das Label betritt -
MouseLeave
... wenn der Mauszeiger das Label verlässt -
MouseMove
... wenn der Mauszeiger innerhalb des Labels bewegt wird -
MouseDown
... wenn eine Maustaste auf dem Label gedrückt wird -
MouseUp
... wenn eine Maustaste auf dem Label losgelassen wird -
MouseHover
... wenn der Mauszeiger für kurze Zeit auf dem Label verweilt
Zustand / Inhalt
- TextChanged
... wenn sich der Text des Labels ändert -
EnabledChanged
... wenn sich der Enabled-Status des Labels ändert -
VisibleChanged
... wenn sich die Sichtbarkeit des Labels ändert
Layout
-
LocationChanged
... wenn sich die Position des Labels ändert -
SizeChanged
... wenn sich die Größe des Labels ändert
Darstellung (Rendering)
- Paint
... wenn das Label neu gezeichnet wird (z. B. bei Aktualisierung oder Überdeckung)
Aussehen
-
FontChanged
... wenn sich die Schriftart des Labels ändert -
ForeColorChanged
... wenn sich die Textfarbe des Labels ändert -
BackColorChanged
... wenn sich die Hintergrundfarbe des Labels ändert
$label.Add_*
param($sender, $e)
$sender→ das Label selbst (=$this)$e→ EventArgs (je nach Event unterschiedlich)
Interaktionen (User Input)
Click / DoubleClick / MouseDown
# Click
$label.Add_Click({
param($sender, $e)
Write-Host "Auf das Label wurde geklickt"
})
# DoubleClick
$label.Add_DoubleClick({
param($sender, $e)
Write-Host "Auf das Label wurde doppelt geklickt"
])
# MouseDown
$label.Add_MouseDown({
param($sender, $e)
Write-Host "Auf das Label wurde entweder mit links oder rechts geklickt"
})
MouseEnter / MouseLeave
Mit MouseEnter und MouseLeave sind Hover-Effekte möglich
$label.Add_MouseEnter({
$this.ForeColor = "Red"
})
$label.Add_MouseLeave({
$this.ForeColor = "Black"
})
MouseMove
Mausbewegung innerhalb vom Label
$label.Add_MouseMove({
param($sender, $e)
})
TextChanged
Wird ausgelöst, wenn sich der Text ändert
$label.Add_TextChanged({
param($sender, $e)
Write-Host "Neuer Text: $($sender.Text)"
})
Tipps & Tricks - Label
Typische Stolperfallen
- Text wird abgeschnitten
→AutoSizevergessen oderSizezu klein - Mehrzeiliger Text funktioniert nicht
→ kein ``n` verwendet oder Größe zu klein - Label wirkt "unsichtbar"
→ForeColor=BackColor - Klick funktioniert nicht wie erwartet
→ Label ist nicht für Interaktion gedacht
Mentales Modell
Ein Label ist UI-Deko mit Bedeutung.
Es erklärt dem Benutzer, was andere Controls tun oder zeigt Status an.
Wann sinnvoll?
- Beschriftung von Eingabefeldern
- Statusanzeigen
- Überschriften / Struktur
Wann vermeiden?
- Wenn Interaktion erwartet wird → Button nutzen
- Wenn komplexe Darstellung nötig ist → anderes Control prüfen
ListBox
Namespace: System.Windows.Forms

Die ListBox ist eines dieser Controls, die simpel wirken, aber erstaunlich schnell chaotisch werden, wenn man sie nicht im Griff hat. Im Kern zeigt sie eine Liste von Einträgen an, aus denen der Benutzer auswählen kann.
# ListBox erstellen
$listBox = New-Object System.Windows.Forms.ListBox
$listBoxNew = [System.Windows.Forms.ListBox]::new()
# Größe & Position
$listBox.Size = New-Object System.Drawing.Size(200,150)
$listBox.Location = New-Object System.Drawing.Point(10,10)
# Items hinzufügen
$listBox.Items.Add("Apfel")
$listBox.Items.Add("Banane")
$listBox.Items.Add("Kirsche")
# Mehrere auf einmal
$listBox.Items.AddRange(@("Orange","Mango","Traube"))
📥 Werte auslesen
# Einzelne Auswahl
$selected = $listBox.SelectedItem
# Index
$index = $listBox.SelectedIndex
# Mehrere auswählen
$selectedItems = $listBox.SelectedItems
Events
- Event – Hinweistext
Auslöser / Trigger dieses Events
- SelectedIndexChanged
Wird ausgelöst, sobald sich die Auswahl ändert. - SelectedValueChanged
Fast wieSelectedIndexChanged, aber subtil anders.
Feuert, wenn sich der Value ändert (relevant beiValueMember)
Click
Löst bei jedem Klick auf das Control aus- DoubleClick
Feuert, beim Doppelklick auf das Control / oder ein Item - MouseDown
Feuert vor dem Click - MouseUp
Feuert nach dem Click
KeyDown
Wird ausgelöst, wenn eine Taste gedrückt wird- KeyUp
SowieKeyDown, aber erst wenn losgelassen wird
Events - ListBox
SelectedIndexChanged
Wird ausgelöst, sobald sich die Auswahl ändert.
$listBox.Add_SelectedIndexChanged({
Write-Host "Ausgewählt:" $listBox.SelectedItem
})
SelectedValueChanged
Fast wie SelectedIndexChanged… aber subtil anders.
Feuert, wenn sich der Value ändert (relevant bei ValueMember).
$listBox.Add_SelectedValueChanged({
Write-Host "Value geändert:" $listBox.SelectedItem
})
👉 Unterschied merkst du erst, wenn du mit Objekten arbeitest.
Click
Wird bei jedem Klick ausgelöst.
Ja, auch wenn sich nichts ändert. Klassiker für doppelte Logik.
$listBox.Add_Click({
Write-Host "ListBox wurde geklickt"
})
DoubleClick
Wenn der User doppelt klickt. Perfekt für „öffnen“, „starten“, etc.
$listBox.Add_DoubleClick({
Write-Host "Doppelklick auf:" $listBox.SelectedItem
})
👉 UX-technisch oft sinnvoller als Button daneben.
KeyDown
Für Tastatursteuerung. Wird ausgelöst, wenn eine Taste gedrückt wird.
$listBox.Add_KeyDown({
if ($_.KeyCode -eq "Enter") {
Write-Host "Enter auf:" $listBox.SelectedItem
}
})
👉 Das ist der Moment, wo dein UI sich plötzlich „professionell“ anfühlt.
KeyUp
Wie KeyDown, nur nachdem losgelassen wurde.
$listBox.Add_KeyUp({
Write-Host "Taste losgelassen:" $_.KeyCode
})
MouseDown
Feuert vor Click. Gut für spezielle Logik.
$listBox.Add_MouseDown({
Write-Host "MouseDown erkannt"
})
MouseUp
Nach dem Klick.
$listBox.Add_MouseUp({
Write-Host "MouseUp erkannt"
})
Tipps & Tricks - TabControl
Ich sag’s dir direkt, weil ich genau weiß, wie das läuft:
Du kombinierst sowas:
Click
SelectedIndexChanged
DoubleClick
…und wunderst dich, warum dein Code mehrfach läuft.
👉 Beispiel:
-
Klick →
MouseDown -
Klick →
Click -
Auswahl ändert sich →
SelectedIndexChanged
→ Boom, drei Events für einen simplen Klick.
🧩 Mini-Leitfaden (der dir später Nerven spart)
- Auswahl reagieren →
SelectedIndexChanged - Aktion starten →
DoubleClickoderEnter - Nur Klick erkennen →
Click - Präzise Kontrolle →
MouseDown
➕ Items verwalten
# Entfernen
$listBox.Items.Remove("Apfel")
# Alles löschen
$listBox.Items.Clear()
# Einfügen an Position
$listBox.Items.Insert(0, "Neu")
🎨 Nützliche Tricks
Automatisch sortieren
$listBox.Sorted = $true
Mehrspaltig anzeigen
$listBox.MultiColumn = $true
Scrollbar erzwingen
$listBox.HorizontalScrollbar = $true
⚠️ Typische Stolperfallen
-
SelectedItemist$null, wenn nichts gewählt ist → obvious, aber wird ständig vergessen -
SelectedItemsist kein Array, sondern Collection → verhält sich leicht anders -
Bei
MultiExtended: Benutzer müssen STRG drücken → sonst denkt jeder, dein UI ist kaputt -
Items.AddRange()erwartet ein Array → kein wild zusammengebauter String-Müll
🧩 Best Practice
-
Für einfache Auswahl →
ListBox -
Für strukturierte Daten → ListView (sonst wird’s hässlich)
-
Für kleine Auswahl → lieber ComboBox
Ich greif einen Punkt raus, den du wahrscheinlich unterschätzt:
Was speicherst du eigentlich in der ListBox? Strings oder Objekte?
Wenn du nur Strings reinwirfst, verbaust du dir später jede sinnvolle Logik.
Pack lieber direkt Objekte rein:
$listBox.Items.Add([PSCustomObject]@{
Name = "Chrome"
Version = "123"
})
Und dann:
$listBox.DisplayMember = "Name"
Das ist der Unterschied zwischen „funktioniert irgendwie“ und „ich hab Kontrolle über meinen Code“.
Das ist so ein klassischer Punkt, wo Leute sich später selbst hassen, weil sie am Anfang “einfach schnell Strings genommen haben”.
RichTextBox
Namespace: System.Windows.Forms
Properties / Eigenschaften
- Property – Standardwert
Beschreibung oder Erläuterung der Eigenschaft
-
BackColor – SystemColors.Window
Hintergrundfarbe der RichTextBox -
BorderStyle – Fixed3D
Rahmenstil (None,FixedSingle,Fixed3D) -
Font – Standard-Systemfont
Schriftart und -größe -
ForeColor – SystemColors.WindowText
Textfarbe -
HideSelection – $true
Steuert, ob der Text im nicht markierten Zustand verborgen wird -
Text – ""
Der gesamte Text in der RichTextBox -
WordWrap – $true
Zeilenumbruch aktivieren/deaktivieren -
Rtf – ""
Ruft den RTF-Inhalt der RichTextBox ab oder setzt ihn -
Multiline – $true
Zeigt Text auf mehreren Zeilen -
SelectionAlignment – Left
Ausrichtung des Textes in der aktuellen Auswahl (Left,Center,Right) -
SelectionColor – SystemColors.HighlightText
Farbe der ausgewählten Textstellen -
SelectionFont – Standard-Schrift
Schriftart der Auswahl -
SelectionBackColor – SystemColors.Highlight
Hintergrundfarbe der Auswahl -
SelectionLength – 0
Länge der aktuellen Auswahl -
SelectionStart – 0
Der Startindex der aktuellen Auswahl -
TextChanged – $false
Event wird ausgelöst, wenn sich der Text ändert
Die RichTextBox ist eine erweiterte Textbox, die es ermöglicht, formatierte Textinhalte darzustellen und zu bearbeiten. Sie unterstützt RTF (Rich Text Format) sowie einfache Textformate.
Erstellen
# Erstellen
$richTextBox = New-Object System.Windows.Forms.RichTextBox
$richTextBoxNew = [System.Windows.Forms.RichTextBox]::new()
# Größe & Position
$richTextBox.Size = New-Object System.Drawing.Size(400, 200)
$richTextBox.Location = New-Object System.Drawing.Point(10,10)
# Text setzen
$richTextBox.Text = "Hallo, dies ist ein Testtext in der RichTextBox!"
# Formatierter Text (RTF)
$richTextBox.Rtf = "{\rtf1\ansi\ansicpg1252\uc1\pard\lang1031\f0\fs20 Hallo, \b dies ist ein \i Test \b0\i0 Text.\par}"
📥 Werte auslesen
# Einfacher Text
$plainText = $richTextBox.Text
# RTF-Text
$rtfText = $richTextBox.Rtf
# Auswahl
$selectedText = $richTextBox.SelectedText
👉 Unterschied:Text gibt nur den normalen Text zurück, während Rtf den gesamten formatierten Text (inklusive Formatierung) liefert.
Events - RichTextBox
TextChanged
Wird ausgelöst, wenn sich der Text in der RichTextBox ändert.
$richTextBox.Add_TextChanged({
Write-Host "Text hat sich geändert!"
})
SelectionChanged
Wenn der Benutzer die Auswahl ändert, wird dieses Event ausgelöst.
$richTextBox.Add_SelectionChanged({
Write-Host "Neue Auswahl: $($richTextBox.SelectedText)"
})
LinkClicked
Wenn der Benutzer auf einen Link klickt, wird dieses Event ausgelöst.
$richTextBox.Add_LinkClicked({
param($sender, $e)
Write-Host "Link angeklickt: $($e.Link)"
})
Tipps & Tricks
Formatierter Text
$richTextBox.SelectionColor = "Red"
$richTextBox.SelectionFont = New-Object System.Drawing.Font("Arial", 12, [System.Drawing.FontStyle]::Bold)
$richTextBox.AppendText(" Dies ist ein Text mit roter Schrift und fettem Arial.")
RTF-Inhalt speichern
# RTF in Datei speichern
$richTextBox.SaveFile("C:\Pfad\zur\Datei.rtf", [System.Windows.Forms.RichTextBoxStreamType]::RichText)
Hyperlinks hinzufügen
$richTextBox.AppendText("Hier klicken: ")
$richTextBox.InsertLink("https://www.example.com")
⚠️ Typische Stolperfallen
- Text wird nicht formatiert, aber du hast vergessen, den richtigen Stream (RTF vs. Text) zu verwenden.
- Events feuern zu oft: Achte darauf, dass du nicht zu viele Events auslöst. Besonders
TextChangedist gefährlich, weil es oft auch bei jeder kleinen Änderung feuert.
🧩 Best Practice
- Für einfache Textfelder immer die normale
TextBoxverwenden. - Nutze
RichTextBox, wenn du Formatierung und erweiterte Textoptionen brauchst. - RTF ist dein Freund, wenn du komplexe Formatierungen brauchst – ansonsten geht auch normaler Text.
TabControl
Ein TabControl ist ein Container, der mehrere TabPage-Instanzen verwaltet und zwischen ihnen umschaltet.
Es stellt die Tabs (Reiter) dar und bestimmt, welche TabPage aktuell sichtbar ist.
Grundlagen
Das TabControl ist die Steuerung, nicht der Inhalt.
TabControl→ verwaltet TabsTabPage→ enthält den eigentlichen Inhalt
TabControl erstellen
# Klassisch
$tabControl = New-Object System.Windows.Forms.TabControl
# .NET-Style
$tabControl = [System.Windows.Forms.TabControl]::new()
TabPage hinzufügen
Ein TabPage wird nicht direkt zum TabControl hinzugefügt, sondern zur enthaltenen Sammlung $tabControl.TabPages.
Die Sammlung TabPages stellt mehrere Methoden zum Hinzufügen von TabPage-Instanzen bereit:
TabPages.Add($tabPage1)– Fügt dasTabPage$tabPage1zur Sammlung hinzuTabPages.AddRange(@($tabPage2, $tabPage3))– Fügt mehrereTabPage-Instanzen gleichzeitig als Array hinzuTabPages.Insert(0, $tabPage4)– Fügt dasTabPagean der gewünschten Position innerhalb der Sammlung ein
$tabControl.TabPages.Add($tabPage1)
$tabControl.TabPages.AddRange(@(
$tabPage2,
$tabPage3
))
$tabControl.TabPages.Insert(0, $tabPage4)
# Technisch möglich, aber nicht empfohlen
$tabControl.Controls.Add($tabPage4)
$tabControl.Controls.AddRange(@(
$tabPage5,
$tabPage6
))
Über Add() kann zusätzlich direkt ein neues TabPage erstellt werden:
# Erstellt ein neues TabPage
$tabControl.TabPages.Add("TabText")
# Erstellt ein neues TabPage mit Name + Text
$tabControl.TabPages.Add("TabName", "TabText")
TabPage entfernen
Ein TabPage kann aus dem TabControl mit der Referenz zum TabPage und Remove() oder über den Index mit RemoveAt() entfernt werden.
$tabControl.TabPages.Remove($tabPage1) # mit Referenz
$tabControl.TabPages.RemoveAt(0) # mit Index
Mit Clear() werden alle TabPage-Instanzen entfernt.
# Alle entfernen
$tabControl.TabPages.Clear()
TabPage Auswahl/Zugriff
Mit dem jeweiligen Index vom TabPage, kann in TabPages direkt auf das TabPage zugegriffen werden.
# Zugriff auf einzelnes TabPage
$tabControl.TabPages[0]
# Aktiven Tab setzen
$tabControl.SelectedIndex = 0
$tabControl.SelectedTab = $tabPage1
Eigenschaften
Eigenschaften
- Alignment – Position der Tabs (
Top,Bottom,Left,Right) - Anchor – Verankerung an den Rändern des Parent-Containers
- Appearance – Darstellung der Tabs (
Normal,Buttons,FlatButtons) - Dock – Automatische Ausrichtung im Parent-Container
- DrawMode – Zeichenmodus der Tabs
- HotTrack – Hover-Effekt über Tabs
- ImageList – Sammlung der für Tabs verfügbaren Bilder
- ItemSize – Größe einzelner Tabs (nur relevant bei
SizeMode = Fixed) - Multiline – Mehrere Reihen von Tabs erlauben
- Padding – Innenabstand des Tab-Headers
- RowCount – Anzahl der Tab-Reihen (relevant bei
Multiline) - SelectedImageIndex – Icon für den ausgewählten Tab
- SelectedIndex – Index des aktuell aktiven Tabs
- SelectedTab – Referenz auf die aktuell aktive
TabPage - ShowToolTips – Tooltips für Tabs aktivieren
- SizeMode – Größe der Tabs (
Normal,Fixed) - TabPages – Sammlung aller enthaltenen
TabPage-Instanzen
Alignment [Systems.Windows.Forms.TabAlignment]
Der Wert von Alignment legt fest, an welcher Seite des TabControl die Tabs dargestellt werden. Standardmäßig ist diese Eigenschaft auf Top gesetzt, wodurch sich die Tabs oberhalb des Inhaltsbereichs befinden. Alternativ können die Tabs auch am unteren (Bottom), linken (Left) oder rechten (Right) Rand angezeigt werden. Die Position der Tabs beeinflusst lediglich deren Darstellung und hat keinen Einfluss auf die enthaltenen TabPage-Instanzen oder deren Funktionalität.
Anchor [Systems.Windows.Forms.AnchorStyles]
Der Wert von Anchor legt fest, an welchen Rändern seines Parent-Containers ein Control verankert ist. Standardmäßig ist diese Eigenschaft auf Top, Left gesetzt, wodurch das Control seinen Abstand zum oberen und linken Rand beibehält. Wird die Größe des Parent-Containers verändert, passt das Control seine Position oder Größe entsprechend den festgelegten Verankerungen an.
Mehrere Verankerungen können kombiniert werden. Ist ein Control beispielsweise an Left und Right verankert, wird seine Breite automatisch angepasst, um den Abstand zu beiden Rändern beizubehalten. Durch die Kombination verschiedener Werte lässt sich das Verhalten eines Controls bei Größenänderungen flexibel steuern.
Appearance [System.Windows.Forms.TabAppearance]
Der Wert von Appearance legt fest, wie die Tabs eines TabControl dargestellt werden. Standardmäßig ist diese Eigenschaft auf Normal gesetzt, wodurch die Tabs im klassischen Registerkarten-Stil angezeigt werden. Alternativ können die Tabs als Schaltflächen (Buttons) oder als flache Schaltflächen (FlatButtons) dargestellt werden.
- Normal → klassische Registerkarten
- Buttons → Tabs werden wie normale Schaltflächen dargestellt
- FlatButtons → Tabs werden wie flache Schaltflächen dargestellt
Die Eigenschaft beeinflusst ausschließlich das Erscheinungsbild der Tabs und hat keinen Einfluss auf die Funktionalität des TabControl oder der enthaltenen TabPage-Instanzen. Unabhängig von der gewählten Darstellung können Tabs weiterhin ausgewählt und gewechselt werden.
Dock [Systems.Windows.Forms.DockStyle]
Der Wert von Dock legt fest, an welcher Seite seines Parent-Containers ein Control angedockt wird. Standardmäßig ist diese Eigenschaft auf None gesetzt, wodurch die Position und Größe des Controls ausschließlich durch dessen Location- und Size-Eigenschaften bestimmt werden. Alternativ kann das Control an den oberen (Top), unteren (Bottom), linken (Left) oder rechten (Right) Rand angedockt oder mit Fill auf die gesamte verfügbare Fläche des Parent-Containers ausgedehnt werden.
Im Gegensatz zu Anchor bestimmt Dock nicht die Abstände zu den Rändern, sondern übernimmt die automatische Positionierung und Größenanpassung des Controls. Wird beispielsweise Fill verwendet, füllt das Control den gesamten verfügbaren Bereich seines Parent-Containers aus.
DrawMode [Systems.Windows.Forms.TabDrawMode]
Der Wert von DrawMode legt fest, wie die Tabs des TabControl gezeichnet werden. Standardmäßig ist diese Eigenschaft auf Normal gesetzt, wodurch das Betriebssystem die Darstellung der Tabs vollständig übernimmt. Wird DrawMode auf OwnerDrawFixed gesetzt, ist der Entwickler für das Zeichnen der Tabs verantwortlich und kann deren Aussehen individuell gestalten.
Die Einstellung OwnerDrawFixed wird häufig verwendet, um eigene Farben, Schriftarten oder Symbole für Tabs darzustellen. Da die Tabs dabei selbst gezeichnet werden müssen, wird zusätzlich das DrawItem-Event benötigt, in dem die eigentliche Darstellung implementiert wird.
HotTrack [System.Boolean]
Der Wert von HotTrack legt fest, ob Tabs auf Mausbewegungen reagieren sollen. Standardmäßig ist diese Eigenschaft auf False gesetzt, wodurch Tabs ihr Aussehen beim Überfahren mit dem Mauszeiger nicht verändern. Wird HotTrack auf True gesetzt, hebt das TabControl den Tab unter dem Mauszeiger visuell hervor, um die Interaktion für den Benutzer deutlicher zu machen.
ImageList [Systems.Windows.Forms.ImageList]
Der Wert von ImageList legt die Bildersammlung fest, aus der die Tabs ihre Symbole beziehen. Standardmäßig ist diese Eigenschaft auf $null gesetzt, wodurch keine Symbole angezeigt werden. Die Eigenschaft dient lediglich als Quelle der verfügbaren Bilder. Welche Bilder tatsächlich in den Tab-Headern angezeigt werden, wird über die Eigenschaften ImageIndex oder ImageKey der jeweiligen TabPage festgelegt.
ItemSize [System.Drawing.Size]
Der Wert von ItemSize legt die Größe der einzelnen Tabs fest. Standardmäßig besitzt diese Eigenschaft den Wert (Width=0, Height=0), wodurch die Größe der Tabs automatisch durch das TabControl bestimmt wird. Die Eigenschaft wird erst relevant, wenn SizeMode auf Fixed gesetzt ist. In diesem Fall verwendet das TabControl die in ItemSize festgelegte Breite und Höhe für alle Tabs.
Multiline [System.Boolean]
Der Wert von Multiline legt fest, ob die Tabs auf mehrere Reihen verteilt werden dürfen. Standardmäßig ist diese Eigenschaft auf False gesetzt, wodurch alle Tabs in einer einzelnen Reihe dargestellt werden. Wird Multiline auf True gesetzt, erstellt das TabControl bei Platzmangel automatisch zusätzliche Reihen, sodass alle Tabs sichtbar bleiben können.
Padding [System.Windows.Forms.Padding]
Der Wert von Padding legt den Innenabstand innerhalb der Tab-Header fest. Standardmäßig ist diese Eigenschaft auf (6, 3) gesetzt. Dadurch wird zwischen dem Rand eines Tabs und dessen Inhalt, beispielsweise dem Text oder einem Icon, ein zusätzlicher Abstand eingefügt.
Die Eigenschaft beeinflusst nicht den Inhalt der enthaltenen TabPage-Instanzen, sondern ausschließlich die Darstellung der Tabs selbst. Durch größere Werte kann mehr Platz zwischen dem Rand eines Tabs und dessen Inhalt geschaffen werden, während kleinere Werte zu einer kompakteren Darstellung führen.
RowCount [System.Int32]
Der Wert von RowCount gibt an, aus wie vielen Reihen die Tabs aktuell bestehen. Standardmäßig beträgt der Wert 0, solange sich keine TabPage im TabControl befindet. Die Eigenschaft wird vom TabControl automatisch ermittelt und kann nicht direkt festgelegt werden. Besonders relevant ist RowCount, wenn Multiline auf True gesetzt ist, da die Tabs dann auf mehrere Reihen verteilt werden können.
SelectedImageIndex [System.Int32]
Der Wert von SelectedImageIndex legt den Index des Bildes fest, das für den aktuell ausgewählten Tab verwendet werden soll. Standardmäßig ist diese Eigenschaft auf -1 gesetzt, wodurch kein spezielles Bild für den aktiven Tab definiert ist. Die Bilder werden dabei aus der dem TabControl zugewiesenen ImageList bezogen.
Ist ein gültiger Bildindex angegeben, kann für den ausgewählten Tab ein anderes Symbol als für die übrigen Tabs dargestellt werden. Die Eigenschaft wird hauptsächlich in Verbindung mit einer ImageList verwendet und hat ohne zugewiesene Bilder keine sichtbare Auswirkung.
SelectedIndex [System.Int32]
Der Wert von SelectedIndex entspricht dem Index des aktuell aktiven TabPage. Die TabPages-Collection ist 0-basiert, weshalb das erste TabPage den Index 0 besitzt. Befindet sich mindestens ein TabPage im TabControl, ist standardmäßig das erste TabPage aktiv. Ist die TabPages-Collection leer, beträgt der Wert von SelectedIndex -1.
SelectedTab [System.Windows.Forms.TabPage]
Der Wert von SelectedTab enthält eine Referenz auf die aktuell aktive TabPage des TabControl. Standardmäßig ist diese Eigenschaft auf $null gesetzt, solange sich keine TabPage in der TabPages-Collection befindet. Sobald mindestens ein TabPage vorhanden ist, verweist SelectedTab auf das aktuell ausgewählte TabPage. Über diese Eigenschaft kann sowohl das aktive TabPage ausgelesen als auch ein anderes TabPage direkt ausgewählt werden.
ShowToolTips [System.Boolean]
Der Wert von ShowToolTips legt fest, ob für die Tabs eines TabControl Tooltips angezeigt werden dürfen. Standardmäßig ist diese Eigenschaft auf $false gesetzt, wodurch keine Tooltips dargestellt werden. Wird ShowToolTips auf $true gesetzt, können einzelnen TabPage-Instanzen Tooltip-Texte zugewiesen werden, die beim Überfahren des jeweiligen Tabs mit dem Mauszeiger angezeigt werden.
SizeMode [Systems.Windows.Forms.TabSizeMode]
Der Wert von SizeMode legt fest, wie die Größe der einzelnen Tabs bestimmt wird. Standardmäßig ist diese Eigenschaft auf Normal gesetzt, wodurch die Breite jedes Tabs automatisch anhand seines Inhalts berechnet wird. Wird SizeMode auf Fixed gesetzt, erhalten alle Tabs dieselbe Größe, die über die Eigenschaft ItemSize festgelegt werden kann.
TabPages [Systems.Windows.Forms.TabControl.TabPageCollection]
Der Wert von TabPages enthält die Sammlung aller TabPage-Instanzen, die dem TabControl hinzugefügt wurden. Standardmäßig ist diese Sammlung leer. Über TabPages können TabPage-Instanzen hinzugefügt, entfernt oder anhand ihres Indexes bzw. ihrer Referenz abgerufen werden. Die Reihenfolge der Elemente innerhalb der Sammlung entspricht dabei der Reihenfolge der Tabs im TabControl.
Methoden
Methoden
TabControl
- GetTabRect – Gibt die Position und Größe vom TabPage-Reiter zurück
TabControl.TabPages
- Add – Fügt eine
TabPage-Instanz hinzu - AddRange – Fügt mehrere
TabPage-Instanzen hinzu - Clear – Entfernt alle
TabPage-Instanzen - Insert – Fügt eine
TabPage-Instanz an einer gewünschten Stelle hinzu - Remove – Entfernt eine
TabPage-Instanz - RemoveAt – Entfernt mit dem Index eine
TabPage-Instanz
TabControl
GetTabRect()
Datentyp: [System.Drawing.Rectangle]
Rückgabewert: Position und Größe des Tab-Headers
GetTabRect( Index )
Die Methode GetTabRect() gibt die Position und Größe eines Tabs innerhalb des TabControl zurück.
Über den angegebenen Index wird festgelegt, für welchen Tab die Informationen ermittelt werden sollen. Der Rückgabewert ist ein Rectangle, das die Position sowie die Breite und Höhe des entsprechenden Tab-Headers enthält. Die zurückgegebenen Koordinaten beziehen sich auf das TabControl selbst.
Die Methode wird häufig verwendet, um Mausklicks auf einzelne Tabs zu erkennen oder um eigene Zeichnungslogik mit OwnerDrawFixed umzusetzen.
TabControl.TabPages
Add()
$_.TabPages.Add( $tabPage )
# → vorhandenes TabPage hinzufügen
Die Methode Add() fügt eine TabPage zur TabPages-Collection hinzu. Das TabPage wird dabei am Ende der Sammlung eingefügt und erscheint als neuer Tab im TabControl.
Nach dem Hinzufügen kann das TabPage über die TabPages-Collection, SelectedIndex oder SelectedTab verwendet werden.
$_.TabPages.Add( "Text" )
# → Neues TabPage mit Text erstellen
Der übergebene Text wird dabei als Beschriftung des Tabs verwendet.
$_.TabPages.Add( "Name", "Text" )
# → Neues TabPage mit Name und Text erstellen
Hierbei wird sowohl der interne Name als auch die sichtbare Beschriftung (Text) festgelegt.
Diese Varianten eignen sich für einfache Tabs, bei denen keine weiteren Eigenschaften unmittelbar gesetzt werden müssen.
AddRange()
$_.TabPages.AddRange( $tabPages )
Die Methode AddRange() fügt mehrere TabPage-Instanzen gleichzeitig zur TabPages-Collection hinzu.
Die Reihenfolge der Elemente im Array entspricht anschließend der Reihenfolge der Tabs im TabControl. Die Tabs werden dabei am Ende der vorhandenen Sammlung eingefügt.
Clear()
$_.TabPages.Clear()
Die Methode Clear() entfernt alle TabPage-Instanzen aus der TabPages-Collection.
Nach dem Aufruf enthält das TabControl keine Tabs mehr. Existiert kein Tab mehr, besitzen Eigenschaften wie SelectedIndex den Wert -1 und SelectedTab den Wert $null.
Insert()
$_.TabPages.Insert( Index, $tabPage )
Die Methode Insert() fügt eine TabPage an einer bestimmten Position innerhalb der TabPages-Collection ein.
Bereits vorhandene Einträge werden ab dieser Position um eine Stelle nach hinten verschoben. Dadurch kann die Reihenfolge der Tabs gezielt beeinflusst werden.
Remove()
$_.TabPages.Remove( $tabPage )
Die Methode Remove() entfernt eine bestimmte TabPage aus der TabPages-Collection.
Das TabPage selbst wird dabei nicht gelöscht, sondern lediglich aus dem TabControl entfernt. Es kann später erneut einer TabPages-Collection hinzugefügt werden.
RemoveAt()
$_.TabPages.RemoveAt( Index )
Die Methode RemoveAt() entfernt die TabPage an der angegebenen Position aus der TabPages-Collection.
Die verbleibenden Einträge rücken anschließend entsprechend nach vorne auf. Dadurch können sich die Indizes nachfolgender TabPages ändern.
Events
Events
- Selecting – Vor dem Wechsel zum TabPage
- Selected – Nach dem Wechsel zum TabPage
- Deselecting – Vor dem Verlassen vom TabPage
- Deselected – Nach dem Verlassen vom TabPage
- SelectedIndexChanged – Ausgewählter TabPage hat sich geändert
- Click – Mausklick auf das TabControl
- DoubleClick – Doppelklick auf das TabControl
- MouseDown – Maustaste wurde auf dem TabControl gedrückt
- MouseMove – Maus wurde über dem TabControl bewegt
- MouseUp – Gedrückte Maustaste wurde auf dem TabControl losgelassen
- MouseEnter – Mauszeiger betritt den Bereich des TabControl
- MouseLeave – Mauszeiger verlässt den Bereich des TabControl
- DragDrop – Element wurde per Drag&Drop auf dem TabControl abgelegt
- KeyDown – Taste wurde gedrückt während das TabControl den Fokus hat
- ControlAdded – Dem TabControl wurde ein TabPage hinzugefügt
- ControlRemoved – Vom TabControl wurde ein TabPage entfernt
- Resize – Größe des TabControl hat sich geändert
- Paint – TabControl wird neu gezeichnet
$tabControl.Add_*
param($sender, $e)
$sender→ Das TabControl selbst (=$this)$e(EventArgs) → Argumente Tab (TabPage) entsprechend
Tabwechsel
Selecting
Vor dem Wechsel zu einem Tab (TabPage) → kann noch abgebrochen werden
$e.TabPage→ der Tab, zu dem gewechselt werden soll$e.TabPageIndex→ Index davon$e.Cancel→ kannst du auf$truesetzen → Wechsel wird verhindert
Selected
Nach dem Wechsel zu einem Tab (TabPage)
$e.TabPage→ der Tab, zu dem gewechselt wurde$e.TabPageIndex→ Index davon
$tabControl.Add_Selecting({
param($sender, $e)
# Ziel-Tab
$nextTab = $e.TabPage
if ($nextTab.Name -eq "PackageTab") {
Write-Host "Wechsel verhindert!"
# 🚨 DAS ist der Trick:
$e.Cancel = $true
}
})
SelectedIndexChanged
Wird ausgelöst, nachdem sich der ausgewählte Tab geändert hat
- ❌ Kein
$e.TabPage - ✅
$sender.SelectedTab→ aktuell aktiver Tab - ✅
$sender.SelectedIndex→ Index des aktiven Tabs
$sender, $e
$sender
$sender.SelectedTab→ aktuell aktiver Tab (TabPage)$sender.SelectedIndex→ Index davon$sender.TabPages→ alle Tabs (Collection)$sender.TabCount→ Anzahl Tabs$sender.Name→ Name vom Control$sender.Enabled→ ob aktiv$sender.Visible→ sichtbar oder nicht
$e
- einfach nur ein Standard-EventArgs-Objekt
- ohne nützliche Zusatzinfos
$tabControl.Add_SelectedIndexChanged({
param($sender, $e)
# Aktueller Tab
$currentTab = $sender.SelectedTab
Write-Host "Aktiver Tab: $($currentTab.Name)"
})
Deselecting
Vor dem Verlassen eines Tabs (TabPage) → kann noch abgebrochen werden
$tabControl.Add_Deselecting({
param($sender, $e)
# Aktueller Tab (der verlassen wird)
$currentTab = $e.TabPage
# Beispiel: Verhindere Verlassen wenn noch Auswahl vorhanden
if ($currentTab.Name -eq "PackageTab" -and $checkedListBox.CheckedItems.Count -gt 0) {
Write-Host "Du hast noch Auswahl!"
$e.Cancel = $true
}
})
$e (EventArgs)
• $e.TabPage → der Tab, der verlassen wird
• $e.Cancel → $true = Wechsel wird verhindert
Deselected
Nach dem Verlassen eines Tabs → ideal zum Zurücksetzen von UI
$tabControl.Add_Deselected({
param($sender, $e)
# Verlassener Tab
$oldTab = $e.TabPage
if ($oldTab.Name -eq "PackageTab") {
# CheckedListBox zurücksetzen
for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) {
$checkedListBox.SetItemChecked($i, $false)
}
# ListBox zurücksetzen
$listBox.ClearSelected()
}
})
$e (EventArgs)
• $e.TabPage → der Tab, der verlassen wurde
🔍 Konkreter Ablauf beim Tabwechsel
Wenn du von Tab A → Tab B wechselst:
Deselecting(TabControl)
→ bevor Tab A verlassen wird
→ kann abgebrochen werden ($_.Cancel = $true)Selecting(TabControl)
→ bevor Tab B aktiviert wird
→ kann ebenfalls abgebrochen werden
👉 Wenn hier keiner abbricht, geht’s weiter:
Deselected(TabControl)
→ Tab A wurde gerade deaktiviertSelectedIndexChanged(TabControl)
→ der Index hat sich geändertSelected(TabControl)
→ Tab B ist jetzt aktivLeave(TabPage A)
→ Fokus verlässt alten TabEnter(TabPage B)
→ Fokus betritt neuen Tab
Click
Klick auf das Control (selten relevant)
MouseDown
Klick einer beliebigen Maustaste auf dem TabControl
ControlAdded / ControlRemoved
Wenn TabPages hinzugefügt oder entfernt werden. Wird ausgelöst, wenn ein TabPage zur TabPages-Collection
hinzugefügt oder daraus entfernt wird.
Tipps & Tricks - TabControl
Typische Stolperfallen
- Tab wird nicht angezeigt
→ nicht zurTabPages-Collection hinzugefügt - Events greifen nicht
→ falsches Event verwendet (Selectingvs.SelectedIndexChanged) - Layout wirkt falsch
→Dock/Anchornicht sauber gesetzt - Icons fehlen
→ImageListnicht gesetzt oder falscher Index
Mentales Modell
Das TabControl ist ein Container mit Umschalter-Logik.
Es zeigt genau eine TabPage gleichzeitig
und verwaltet nur, welche sichtbar ist.
Wann sinnvoll?
- Strukturierung komplexer Inhalte
- Einstellungen / Optionen
- Platz sparen
Wann vermeiden?
- Häufiges Hin- und Herspringen notwendig
- Linearer Workflow
- Stark voneinander abhängige Inhalte
TableLayoutPanel
1. Grid-Struktur
Ein TableLayoutPanel ist im Kern ein dynamisches Raster aus:
-
RowCount -
ColumnCount -
RowStyles -
ColumnStyles
Die Styles bestimmen wie der Platz verteilt wird, nicht nur wie viele Zellen existieren.
TabPage
Eine TabPage ist im Grunde eine einzelne Seite innerhalb eines TabControl.
Sie stellt den Inhalt dar, der angezeigt wird, wenn ein bestimmter Tab ausgewählt ist.
Eigenschaften
Beispiel Eigenschaft
- Eigenschaft– Standardwert
Beschreibung oder Erläuterung der Eigenschaft
- Text –
Der Titel des Tabs (sichtbar im Reiter) - Name –
Interner Name zur Referenzierung im Code - Controls –
Sammlung aller enthaltenen Controls - Dock –
Bestimmt, wie sich die TabPage innerhalb desTabControlverhält
(meist automatischFill, alles andere ist selten sinnvoll) - Enabled –
Legt fest, ob der Tab auswählbar ist - Visible –
Bestimmt, ob der Tab angezeigt wird - ForeColor –
Farben der Seite (abhängig vom Theme) - BackColor –
Farben der Seite (abhängig vom Theme) - Padding –
Innenabstand zum Rand
Grundidee
Ein TabControl ist der Container für die jeweiligen TabPage-Instanzen.TabPage beinhaltet den sichtbaren Inhalt und TabControl ist das möglichmachende Gerüst.
Beispiel (PowerShell)
$tabControl = [System.Windows.Forms.TabControl]::New()
# Erstellen
$tabPage1 = New-Object System.Windows.Forms.TabPage
$tabPage2 = [System.Windows.Forms.TabPage]::New()
# Hinzufügen
$tabControl.TabPages.Add($tabPage2) # TabPage → TabControl
# Erstellen & Hinzufügen
$tabControl.TabPages.Add("Dritter Tab") # Text = "Dritter Tab"
$tabControl.TabPages.Add("tabPage4", "Vierter Tab") # Name = "tabPage4", Text = "Vierter Tab"
Controls hinzufügen
$button = New-Object System.Windows.Forms.Button
$button.Text = "Klick mich"
$tabPage1.Controls.Add($button)
Wichtig:
Controls werden immer direkt zur TabPage hinzugefügt, nicht zum TabControl.
Tab wechseln (programmatisch)
$tabControl.SelectedTab = $tabPage2
oder
$tabControl.SelectedIndex = 1
Events
TabPage selbst hat keine super-spezifischen Events wie das TabControl.
Sie verhält sich eher wie ein normales Panel.
Trotzdem gibt es ein paar relevante:
-
Enter
Wird ausgelöst, wenn die TabPage aktiv wird (Tab wird ausgewählt) -
Leave
Wird ausgelöst, wenn die TabPage verlassen wird -
Click
Klick irgendwo auf der TabPage (nicht super hilfreich in der Praxis) -
ControlAdded / ControlRemoved
Wenn Controls dynamisch hinzugefügt oder entfernt werden -
Paint
Wenn die TabPage neu gezeichnet wird (Custom Drawing, eher selten)
Wichtig: Tab-Wechsel-Events liegen am TabControl
Wenn du wirklich auf Tab-Wechsel reagieren willst, bist du hier falsch unterwegs:
-
SelectedIndexChanged -
Selecting -
Selected
Die gehören zum TabControl, nicht zur TabPage.
Das ist einer dieser klassischen Momente, wo WinForms dich still verarscht.
Typische Stolperfallen
-
Controls erscheinen nicht
→ falscher Parent (nicht der TabPage hinzugefügt) -
Layout wirkt kaputt
→ falschesDock/Anchorinnerhalb der TabPage -
Events feuern nicht wie erwartet
→ falsches Objekt (TabPage vs. TabControl verwechselt)
Mentales Modell
Denk nicht in "Tabs".
Denk in Panels mit Umschalter.
Jede TabPage ist einfach ein eigenes Panel.
Das TabControl entscheidet nur, welches sichtbar ist.
Wann sinnvoll?
-
Einstellungen gruppieren
-
Inhalte strukturieren
-
Platz sparen
Wann vermeiden?
-
Wenn Nutzer ständig wechseln müssen
-
Wenn Inhalte stark zusammenhängen
GroupBox
Eine GroupBox ist ein Container zur visuellen Gruppierung von Controls.
Sie dient hauptsächlich dazu, zusammengehörige Eingabefelder, Optionen oder Steuerelemente optisch voneinander abzugrenzen.
Der Text der GroupBox wird als Überschrift im Rahmen dargestellt
Basics
Das GroupBox selbst enthält keine besondere Logik.
-
GroupBox→ Container mit Beschriftung -
enthaltene Controls → eigentlicher Inhalt
GroupBox erstellen
# Klassisch
$groupBox = New-Object System.Windows.Forms.GroupBox
# .NET-Style
$groupBox = [System.Windows.Forms.GroupBox]::new()
Controls hinzufügen
Controls werden über die Controls-Collection hinzugefügt.
$groupBox.Controls.Add($textBox)
$groupBox.Controls.AddRange(@(
$label,
$button
))
Controls entfernen
$groupBox.Controls.Remove($textBox)
$groupBox.Controls.Clear()
Eigenschaften
Eigenschaften / Propertys
-
Text – Überschrift der GroupBox
-
Controls – Enthaltene Controls
-
Anchor – Verankerung an den Rändern des Parent-Containers
-
Dock – Automatische Ausrichtung im Parent-Container
-
AutoSize – Größe automatisch an Inhalt anpassen
-
Enabled – Aktiviert oder deaktiviert enthaltene Controls
-
Visible – Sichtbarkeit der GroupBox
-
Font – Schriftart der Überschrift
-
ForeColor – Farbe der Überschrift
-
Padding – Innenabstand für enthaltene Controls
Text [System.String]
Der Wert von Text bestimmt die Beschriftung der GroupBox.
Standardmäßig ist der Wert leer.
$groupBox.Text = "Office Installation"
Controls [System.Windows.Forms.Control.ControlCollection]
Enthält alle Controls, die sich innerhalb der GroupBox befinden.
$groupBox.Controls.Add($button)
Enabled [System.Boolean]
Legt fest, ob die GroupBox aktiviert ist.
Wird Enabled auf $false gesetzt, werden auch alle enthaltenen Controls deaktiviert.
$groupBox.Enabled = $false
Padding [System.Windows.Forms.Padding]
Legt den Innenabstand fest, der zwischen Rahmen und enthaltenen Controls eingehalten wird.
$groupBox.Padding = 10
Methoden
GroupBox.Controls
Methoden – Controls
-
Add – Fügt ein Control hinzu
-
AddRange – Fügt mehrere Controls hinzu
-
Remove – Entfernt ein Control
-
Clear – Entfernt alle Controls
Add()
$_.Controls.Add($control)
Die Methode Add() fügt ein Control zur Controls-Collection der GroupBox hinzu.
AddRange()
$_.Controls.AddRange(@(
$label,
$textbox,
$button
))
Die Methode AddRange() fügt mehrere Controls gleichzeitig zur Controls-Collection hinzu.
Remove()
$_.Controls.Remove($control)
Die Methode Remove() entfernt ein bestimmtes Control aus der GroupBox.
Clear()
$_.Controls.Clear()
Die Methode Clear() entfernt alle enthaltenen Controls.
Events
Events
-
Click – Mausklick auf die GroupBox
-
DoubleClick – Doppelklick auf die GroupBox
-
MouseDown – Maustaste wurde gedrückt
-
MouseUp – Maustaste wurde losgelassen
-
MouseMove – Maus wurde bewegt
-
MouseEnter – Mauszeiger betritt die GroupBox
-
MouseLeave – Mauszeiger verlässt die GroupBox
-
Enter – Fokus betritt die GroupBox
-
Leave – Fokus verlässt die GroupBox
-
ControlAdded – Ein Control wurde hinzugefügt
-
ControlRemoved – Ein Control wurde entfernt
-
Resize – Größe wurde geändert
-
Paint – GroupBox wird neu gezeichnet
$groupBox.Add_*({
param($sender, $e)
})
-
$sender→ Die GroupBox selbst ($this) -
$e→ EventArgs des jeweiligen Events
ControlAdded / ControlRemoved
Werden ausgelöst, wenn Controls zur Controls-Collection hinzugefügt oder daraus entfernt werden.
$groupBox.Add_ControlAdded({
param($sender, $e)
Write-Host "$($e.Control.Name) wurde hinzugefügt"
})
Tipps & Tricks
Typische Stolperfallen
-
Controls erscheinen nicht
-
Position liegt außerhalb der GroupBox
-
-
Alle Controls werden deaktiviert
-
GroupBox.Enabled = $false
-
-
Padding erzeugt kein automatisches Layout
-
Controls müssen weiterhin selbst positioniert werden
-
-
GroupBox für Layout verwendet
-
Für komplexe Layouts meist besser:
Panel,FlowLayoutPaneloderTableLayoutPanel
-
Mentales Modell
Die GroupBox ist ein Container mit Beschriftung.
Sie gruppiert Controls optisch und logisch, besitzt jedoch keine eigene Inhaltslogik.
Wann sinnvoll?
-
Einstellungen gruppieren
-
Formulare strukturieren
-
Optionen zusammenfassen
-
RadioButtons logisch gruppieren
Wann vermeiden?
-
Komplexe Layouts
-
Scrollbare Bereiche
-
Dynamische Containerlogik
-
Wenn lediglich ein Rahmen benötigt wird