# FlowLayoutPanel

Ein `FlowLayoutPanel` ist ein Layout-Container, der seine enthaltenen Controls automatisch hintereinander anordnet.

Im Gegensatz zu einem normalen `Panel` müssen die enthaltenen Controls nicht über ihre `Location` positioniert werden. Das `FlowLayoutPanel` übernimmt die Anordnung anhand der festgelegten Flussrichtung.

Wird der verfügbare Platz überschritten, können die Controls automatisch in eine neue Zeile beziehungsweise Spalte umgebrochen werden.

```text
Panel
→ freie Positionierung über Location

FlowLayoutPanel
→ automatische Anordnung hintereinander

TableLayoutPanel
→ Anordnung in Zeilen und Spalten
````

---

## Grundlagen

Ein `FlowLayoutPanel` eignet sich besonders für Benutzeroberflächen, bei denen Controls dynamisch nebeneinander oder untereinander angeordnet werden sollen.

Typische Einsatzgebiete sind beispielsweise:

* Button-Leisten
* dynamische Listen von Controls
* Werkzeugleisten
* Filter- und Einstellungsbereiche
* Karten- oder Kachelansichten
* automatisch umbrechende Control-Gruppen

### FlowLayoutPanel erstellen

```powershell
# Klassisch
$flow = New-Object System.Windows.Forms.FlowLayoutPanel

# .NET-Style
$flow = [System.Windows.Forms.FlowLayoutPanel]::new()
```

### Controls hinzufügen

Controls werden wie bei anderen Container-Controls über die `Controls`-Collection hinzugefügt.

```powershell
$flow.Controls.Add($button)
$flow.Controls.Add($label)
$flow.Controls.Add($textBox)
```

Die Position der Controls wird anschließend automatisch durch das Layoutsystem bestimmt.

### Flussrichtung

Standardmäßig werden Controls von links nach rechts angeordnet.

```powershell
$flow.FlowDirection = "LeftToRight"
```

Alternativ kann die Anordnung beispielsweise von oben nach unten erfolgen:

```powershell
$flow.FlowDirection = "TopDown"
```

### Automatischer Umbruch

Ist `WrapContents` aktiviert, werden Controls automatisch in eine neue Zeile oder Spalte verschoben, sobald der verfügbare Platz nicht mehr ausreicht.

```powershell
$flow.WrapContents = $true
```

Dadurch kann sich das Layout automatisch an die Größe des Containers anpassen.

---

# Eigenschaften

| Eigenschaft     | Beschreibung                                                                                |
| --------------- | ------------------------------------------------------------------------------------------- |
| `AutoScroll`    | Aktiviert automatisch Scrollleisten, wenn der Inhalt den verfügbaren Bereich überschreitet. |
| `AutoSize`      | Passt die Größe des Panels automatisch an seinen Inhalt an.                                 |
| `BackColor`     | Legt die Hintergrundfarbe des Panels fest.                                                  |
| `BorderStyle`   | Bestimmt die Darstellung des Rahmens.                                                       |
| `Controls`      | Enthält alle Controls des Panels.                                                           |
| `Dock`          | Dockt das Panel an einer Seite seines Parent-Containers an.                                 |
| `FlowDirection` | Bestimmt die Richtung, in der Controls angeordnet werden.                                   |
| `Location`      | Bestimmt die Position des Panels im Parent-Container.                                       |
| `Margin`        | Legt den äußeren Abstand des Panels zu seinem Parent fest.                                  |
| `MaximumSize`   | Definiert die maximal zulässige Größe.                                                      |
| `MinimumSize`   | Definiert die minimal zulässige Größe.                                                      |
| `Name`          | Legt den internen Namen des Panels fest.                                                    |
| `Padding`       | Legt den Innenabstand zwischen Rand und enthaltenen Controls fest.                          |
| `Size`          | Bestimmt Breite und Höhe des Panels.                                                        |
| `WrapContents`  | Legt fest, ob Controls automatisch in eine neue Zeile oder Spalte umgebrochen werden.       |
| `Visible`       | Legt fest, ob das Panel sichtbar ist.                                                       |
| `Enabled`       | Legt fest, ob das Panel und seine enthaltenen Controls verwendet werden können.             |

---

<details>
<summary>AutoScroll</summary>

### **AutoScroll**

**Typ** = `[System.Boolean]`

Der Wert von `AutoScroll` legt fest, ob das `FlowLayoutPanel` automatisch Scrollleisten anzeigt, wenn der enthaltene Inhalt größer als der sichtbare Bereich ist.

Standardmäßig besitzt diese Eigenschaft den Wert `False`.

Ist `AutoScroll` auf `True` gesetzt, werden horizontale und/oder vertikale Scrollleisten angezeigt, sobald die enthaltenen Controls nicht mehr vollständig in den verfügbaren Bereich passen.

```powershell
$flow.AutoScroll = $true
```

> 💡 **Hinweis**
> `AutoScroll` ist besonders nützlich, wenn die Anzahl oder Größe der enthaltenen Controls zur Laufzeit variieren kann.

</details>

---

<details>
<summary>AutoSize</summary>

### **AutoSize**

**Typ** = `[System.Boolean]`

Der Wert von `AutoSize` legt fest, ob sich die Größe des `FlowLayoutPanel` automatisch an seinen Inhalt anpasst.

Standardmäßig besitzt diese Eigenschaft den Wert `False`.

Ist `AutoSize` aktiviert, kann das Panel seine Größe anhand der enthaltenen Controls und deren Layout bestimmen.

```powershell
$flow.AutoSize = $true
```

> 💡 **Hinweis**
> Das tatsächliche Verhalten von `AutoSize` hängt unter anderem von `FlowDirection`, `WrapContents`, `Dock` und den Größen der enthaltenen Controls ab.

</details>

---

<details>
<summary>BackColor</summary>

### **BackColor**

**Typ** = `[System.Drawing.Color]`

Der Wert von `BackColor` legt die Hintergrundfarbe des `FlowLayoutPanel` fest.

```powershell
$flow.BackColor = "WhiteSmoke"
```

</details>

---

<details>
<summary>BorderStyle</summary>

### **BorderStyle**

**Typ** = `[System.Windows.Forms.BorderStyle]`

Der Wert von `BorderStyle` bestimmt, ob und wie das `FlowLayoutPanel` einen sichtbaren Rahmen besitzt.

Folgende Werte stehen zur Verfügung:

* **None** → kein Rahmen
* **FixedSingle** → einfacher Rahmen
* **Fixed3D** → dreidimensionaler Rahmen

```powershell
$flow.BorderStyle = "FixedSingle"
```

</details>

---

<details>
<summary>Controls</summary>

### **Controls**

**Typ** = `[System.Windows.Forms.Control.ControlCollection]`

Die Eigenschaft `Controls` enthält alle Controls, die sich innerhalb des `FlowLayoutPanel` befinden.

Über diese Collection können Controls hinzugefügt, entfernt oder ausgelesen werden.

```powershell
$flow.Controls.Add($button)
```

Mehrere Controls können beispielsweise über eine Schleife hinzugefügt werden:

```powershell
foreach ($button in $buttons) {
    $flow.Controls.Add($button)
}
```

Die Reihenfolge der Controls innerhalb der Collection entspricht dabei grundsätzlich auch der Reihenfolge, in der sie vom Layoutsystem angeordnet werden.

</details>

---

<details>
<summary>Dock</summary>

### **Dock**

**Typ** = `[System.Windows.Forms.DockStyle]`

Der Wert von `Dock` legt fest, an welcher Seite seines Parent-Containers das `FlowLayoutPanel` angedockt wird.

```powershell
$flow.Dock = "Fill"
```

Mit `Fill` nimmt das Panel den gesamten verfügbaren Bereich seines Parent-Containers ein.

Weitere mögliche Werte sind:

* `None`
* `Top`
* `Bottom`
* `Left`
* `Right`
* `Fill`

> 💡 **Hinweis**
> Wird `Dock = "Fill"` verwendet, passt sich das Panel automatisch an die Größe des Parent-Containers an. Dadurch kann insbesondere `WrapContents` seine Wirkung beim Vergrößern oder Verkleinern des Fensters zeigen.

</details>

---

<details>
<summary>FlowDirection</summary>

### **FlowDirection**

**Typ** = `[System.Windows.Forms.FlowDirection]`

Der Wert von `FlowDirection` bestimmt die Richtung, in der die enthaltenen Controls angeordnet werden.

Standardmäßig besitzt diese Eigenschaft den Wert `LeftToRight`.

Folgende Werte stehen zur Verfügung:

| Wert          | Beschreibung                                      |
| ------------- | ------------------------------------------------- |
| `LeftToRight` | Controls werden von links nach rechts angeordnet. |
| `RightToLeft` | Controls werden von rechts nach links angeordnet. |
| `TopDown`     | Controls werden von oben nach unten angeordnet.   |
| `BottomUp`    | Controls werden von unten nach oben angeordnet.   |

```powershell
$flow.FlowDirection = "LeftToRight"
```

Beispiel für eine vertikale Anordnung:

```powershell
$flow.FlowDirection = "TopDown"
```

> 💡 **Hinweis**
> Zusammen mit `WrapContents` bestimmt `FlowDirection`, in welche Richtung das Layout zunächst fließt und wann ein Umbruch erfolgt.

</details>

---

<details>
<summary>Location</summary>

### **Location**

**Typ** = `[System.Drawing.Point]`

Der Wert von `Location` legt die Position des `FlowLayoutPanel` innerhalb seines Parent-Containers fest.

Die Position wird über die X- und Y-Koordinate angegeben.

```powershell
$flow.Location = "20, 40"
```

> 💡 **Hinweis**
> Wird zusätzlich `Dock` verwendet, wird die Position durch das Layoutsystem bestimmt.

</details>

---

<details>
<summary>Margin</summary>

### **Margin**

**Typ** = `[System.Windows.Forms.Padding]`

Der Wert von `Margin` legt den äußeren Abstand des `FlowLayoutPanel` zu seinem Parent-Container fest.

```powershell
$flow.Margin = [System.Windows.Forms.Padding]::new(10)
```

Bei den enthaltenen Controls besitzt `Margin` eine zusätzliche Bedeutung: Das `FlowLayoutPanel` berücksichtigt den Außenabstand der einzelnen Controls bei der automatischen Anordnung.

```powershell
$button.Margin = [System.Windows.Forms.Padding]::new(5)
```

Dadurch entsteht beispielsweise ein Abstand von 5 Pixeln zwischen den einzelnen Controls.

</details>

---

<details>
<summary>MaximumSize</summary>

### **MaximumSize**

**Typ** = `[System.Drawing.Size]`

Der Wert von `MaximumSize` legt die maximal zulässige Größe des `FlowLayoutPanel` fest.

Standardmäßig besitzt diese Eigenschaft den Wert `(0,0)`, wodurch keine Größenbegrenzung besteht.

```powershell
$flow.MaximumSize = "600, 400"
```

</details>

---

<details>
<summary>MinimumSize</summary>

### **MinimumSize**

**Typ** = `[System.Drawing.Size]`

Der Wert von `MinimumSize` legt die minimal zulässige Größe des `FlowLayoutPanel` fest.

```powershell
$flow.MinimumSize = "200, 100"
```

Wird versucht, das Panel kleiner als die angegebene Mindestgröße zu machen, bleibt diese Mindestgröße erhalten.

</details>

---

<details>
<summary>Name</summary>

### **Name**

**Typ** = `[System.String]`

Der Wert von `Name` legt den internen Namen des `FlowLayoutPanel` fest.

Der Name dient ausschließlich zur Identifikation innerhalb des Programms.

```powershell
$flow.Name = "flowButtons"
```

</details>

---

<details>
<summary>Padding</summary>

### **Padding**

**Typ** = `[System.Windows.Forms.Padding]`

Der Wert von `Padding` legt den Innenabstand zwischen dem Rand des `FlowLayoutPanel` und seinen enthaltenen Controls fest.

```powershell
$flow.Padding = [System.Windows.Forms.Padding]::new(10)
```

Dadurch werden die enthaltenen Controls mit einem Abstand von 10 Pixeln zum Rand des Panels angeordnet.

> 💡 **Hinweis**
> `Padding` betrifft den Innenbereich des Panels, während `Margin` den Außenabstand des Panels beziehungsweise der enthaltenen Controls beschreibt.

</details>

---

<details>
<summary>Size</summary>

### **Size**

**Typ** = `[System.Drawing.Size]`

Der Wert von `Size` legt die Breite und Höhe des `FlowLayoutPanel` fest.

```powershell
$flow.Size = "500, 300"
```

Die tatsächliche Größe kann durch `AutoSize`, `Dock` oder andere Layoutmechanismen beeinflusst werden.

</details>

---

<details>
<summary>WrapContents</summary>

### **WrapContents**

**Typ** = `[System.Boolean]`

Der Wert von `WrapContents` legt fest, ob Controls automatisch in eine neue Zeile beziehungsweise Spalte umgebrochen werden, wenn der verfügbare Platz nicht mehr ausreicht.

Standardmäßig besitzt diese Eigenschaft den Wert `True`.

```powershell
$flow.WrapContents = $true
```

Bei einem horizontalen Layout:

```text
[Button 1] [Button 2] [Button 3]
[Button 4] [Button 5] [Button 6]
```

Wird `WrapContents` deaktiviert, versucht das `FlowLayoutPanel`, alle Controls in der ursprünglichen Flussrichtung anzuordnen.

```powershell
$flow.WrapContents = $false
```

Bei `LeftToRight` werden die Controls dadurch beispielsweise weiterhin horizontal angeordnet, auch wenn dadurch der verfügbare Bereich überschritten wird.

> 💡 **Hinweis**
> `WrapContents` wirkt immer zusammen mit `FlowDirection`. Die Flussrichtung bestimmt, wohin die Controls zunächst angeordnet werden, während `WrapContents` bestimmt, ob bei fehlendem Platz ein Umbruch erfolgt.

</details>

---

<details>
<summary>Visible</summary>

### **Visible**

**Typ** = `[System.Boolean]`

Der Wert von `Visible` legt fest, ob das `FlowLayoutPanel` sichtbar dargestellt wird.

```powershell
$flow.Visible = $false
```

</details>

---

<details>
<summary>Enabled</summary>

### **Enabled**

**Typ** = `[System.Boolean]`

Der Wert von `Enabled` legt fest, ob das `FlowLayoutPanel` aktiviert ist.

Standardmäßig besitzt diese Eigenschaft den Wert `True`.

```powershell
$flow.Enabled = $false
```

Wird das Panel deaktiviert, werden auch die enthaltenen Controls entsprechend deaktiviert dargestellt beziehungsweise reagieren nicht mehr auf Eingaben.

</details>

---

# Methoden

## Übersicht

| Methode          | Beschreibung                                                                                          |
| ---------------- | ----------------------------------------------------------------------------------------------------- |
| `GetFlowBreak()` | Ermittelt, ob nach einem bestimmten Control ein Zeilen- beziehungsweise Spaltenumbruch erfolgt.       |
| `SetFlowBreak()` | Legt fest, ob nach einem bestimmten Control ein Zeilen- beziehungsweise Spaltenumbruch erfolgen soll. |

---

<details>
<summary>GetFlowBreak()</summary>

### **GetFlowBreak()**

Die Methode `GetFlowBreak()` ermittelt, ob für ein bestimmtes Control ein manueller Umbruch festgelegt wurde.

```powershell
$flow.GetFlowBreak($button)
```

Der Rückgabewert ist ein `Boolean`.

```text
True  → Nach dem Control erfolgt ein Umbruch.
False → Es erfolgt kein manueller Umbruch.
```

Beispiel:

```powershell
if ($flow.GetFlowBreak($button)) {
    Write-Host "Nach dem Button beginnt eine neue Zeile."
}
```

</details>

---

<details>
<summary>SetFlowBreak()</summary>

### **SetFlowBreak()**

Die Methode `SetFlowBreak()` legt fest, ob nach einem bestimmten Control ein manueller Umbruch erfolgen soll.

```powershell
$flow.SetFlowBreak($button, $true)
```

Der erste Parameter bestimmt das Control, nach dem der Umbruch erfolgen soll.

Der zweite Parameter bestimmt, ob der Umbruch aktiviert oder deaktiviert wird.

```powershell
$flow.SetFlowBreak($button, $true)
```

→ Nach dem Button beginnt ein neuer Layoutabschnitt.

```powershell
$flow.SetFlowBreak($button, $false)
```

→ Der manuelle Umbruch wird wieder entfernt.

### Beispiel

```powershell
$flow = [System.Windows.Forms.FlowLayoutPanel]::new()

$button1 = [System.Windows.Forms.Button]::new()
$button1.Text = "Button 1"

$button2 = [System.Windows.Forms.Button]::new()
$button2.Text = "Button 2"

$button3 = [System.Windows.Forms.Button]::new()
$button3.Text = "Button 3"

$flow.Controls.Add($button1)
$flow.Controls.Add($button2)
$flow.Controls.Add($button3)

$flow.SetFlowBreak($button2, $true)
```

Das Layout kann dadurch beispielsweise so aussehen:

```text
[Button 1] [Button 2]
[Button 3]
```

> 💡 **Hinweis**
> `SetFlowBreak()` ist besonders praktisch, wenn einzelne Controls unabhängig von der verfügbaren Breite einen neuen Layoutabschnitt beginnen sollen.

</details>

---

# Events

Das `FlowLayoutPanel` besitzt die üblichen Events eines Windows-Forms-Controls. Besonders relevant sind Events, die durch Änderungen am enthaltenen Layout oder an der `Controls`-Collection ausgelöst werden.

| Event            | Beschreibung                                                   |
| ---------------- | -------------------------------------------------------------- |
| `ControlAdded`   | Wird ausgelöst, wenn ein Control hinzugefügt wird.             |
| `ControlRemoved` | Wird ausgelöst, wenn ein Control entfernt wird.                |
| `Layout`         | Wird ausgelöst, wenn das Layout des Panels neu berechnet wird. |
| `SizeChanged`    | Wird ausgelöst, wenn sich die Größe des Panels ändert.         |

---

<details>
<summary>ControlAdded</summary>

### **ControlAdded**

Das Event `ControlAdded` wird ausgelöst, sobald ein Control zur `Controls`-Collection des `FlowLayoutPanel` hinzugefügt wurde.

```powershell
$flow.Add_ControlAdded({
    param($sender, $e)

    Write-Host "Control hinzugefügt: $($e.Control.Name)"
})
```

Das Event kann beispielsweise verwendet werden, um neu hinzugefügte Controls automatisch zu konfigurieren.

</details>

---

<details>
<summary>ControlRemoved</summary>

### **ControlRemoved**

Das Event `ControlRemoved` wird ausgelöst, sobald ein Control aus der `Controls`-Collection entfernt wurde.

```powershell
$flow.Add_ControlRemoved({
    param($sender, $e)

    Write-Host "Control entfernt: $($e.Control.Name)"
})
```

</details>

---

<details>
<summary>Layout</summary>

### **Layout**

Das Event `Layout` wird ausgelöst, wenn das Layout des `FlowLayoutPanel` neu berechnet wird.

```powershell
$flow.Add_Layout({
    param($sender, $e)

    Write-Host "Layout wurde aktualisiert."
})
```

Das Event kann beispielsweise verwendet werden, wenn auf Änderungen der Größe oder Anordnung der enthaltenen Controls reagiert werden soll.

> ⚠️ **Hinweis**
> Das `Layout`-Event kann relativ häufig ausgelöst werden. Aufwendige Operationen sollten daher nicht unkontrolliert innerhalb dieses Events ausgeführt werden.

</details>

---

# Beispiel

Das folgende Beispiel erstellt ein `FlowLayoutPanel`, das mehrere Buttons automatisch horizontal anordnet und bei Bedarf in eine neue Zeile umbricht.

```powershell
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = [System.Windows.Forms.Form]::new()
$form.Text = "FlowLayoutPanel"
$form.Size = "500, 300"

$flow = [System.Windows.Forms.FlowLayoutPanel]::new()
$flow.Dock = "Fill"
$flow.Padding = [System.Windows.Forms.Padding]::new(10)
$flow.FlowDirection = "LeftToRight"
$flow.WrapContents = $true
$flow.AutoScroll = $true

$form.Controls.Add($flow)

foreach ($i in 1..10) {

    $button = [System.Windows.Forms.Button]::new()
    $button.Text = "Button $i"
    $button.Size = "100, 40"
    $button.Margin = [System.Windows.Forms.Padding]::new(5)

    $flow.Controls.Add($button)
}

$form.ShowDialog()
```

Das Layout passt sich automatisch an die verfügbare Breite des Fensters an:

```text
┌─────────────────────────────────────┐
│ [Button 1] [Button 2] [Button 3]   │
│ [Button 4] [Button 5] [Button 6]   │
│ [Button 7] [Button 8] [Button 9]   │
│ [Button 10]                         │
└─────────────────────────────────────┘
```

Wird das Fenster breiter, können mehr Controls in einer Zeile dargestellt werden. Wird es schmaler, werden die Controls automatisch in weitere Zeilen umgebrochen.

---

# FlowLayoutPanel vs. andere Container

| Control            | Anordnung                             |
| ------------------ | ------------------------------------- |
| `Panel`            | Freie Positionierung über `Location`  |
| `FlowLayoutPanel`  | Automatische Anordnung hintereinander |
| `TableLayoutPanel` | Anordnung in Zeilen und Spalten       |
| `TabPage`          | Container für den Inhalt eines Tabs   |

Ein `FlowLayoutPanel` ist damit besonders dann geeignet, wenn Controls **in einer bestimmten Reihenfolge automatisch angeordnet**, aber nicht an feste Zeilen oder Spalten gebunden werden sollen.

---

# Hinweise

* `FlowDirection` bestimmt die Richtung des Layouts.
* `WrapContents` bestimmt, ob bei fehlendem Platz automatisch umgebrochen wird.
* `Margin` der enthaltenen Controls wird beim Layout berücksichtigt.
* `Padding` des `FlowLayoutPanel` bestimmt den Abstand der Controls zum Rand.
* `SetFlowBreak()` ermöglicht manuelle Umbrüche unabhängig vom verfügbaren Platz.
* `AutoScroll` kann verwendet werden, wenn der Inhalt größer als der sichtbare Bereich werden kann.
* `AutoSize` und `WrapContents` können sich gegenseitig stark auf das Layoutverhalten auswirken.
* `Location` der enthaltenen Controls sollte bei Verwendung eines `FlowLayoutPanel` normalerweise nicht manuell gesetzt werden, da ihre Position vom Layoutsystem bestimmt wird.