# Layouts

Wisej.NET includes several built-in layout engines and allows developers to easily build custom layout engines. This enables implementing layouts of any complexity, beyond what's available using plain CSS in browsers.

Traditional web frameworks using HTML string concatenation and CSS layouts (Blazor, Angular, PHP, ASP.NET, JSP, etc.) support only a fraction of the layouts available in Wisej.NET applications.

Layout engines handle arranging controls in their container. Every control's [`LayoutEngine`](https://docs.wisej.com/api/wisej.web/general/control#layoutengine) property returns the current engine and can be overridden in derived classes. The engine measures preferred size for `AutoSize` controls and arranges position/size of container's direct children.

## Layout Engines

### Default

All controls use the `DefaultLayout` engine, which supports:

* **Absolute positions**: Each child sets its own [`Location`](https://docs.wisej.com/api/wisej.web/general/control#location) and [`Size`](https://docs.wisej.com/api/wisej.web/general/control#size)
* **Docking**: Children can dock to the parent using [`DockStyles`](https://docs.wisej.com/api/wisej.web/enumerations/wisej.web.dockstyle)
* **Anchoring**: Children can anchor their sides to the parent using [`AnchorStyles`](https://docs.wisej.com/api/wisej.web/enumerations/wisej.web.anchorstyles)

#### Docking

Docking applies to child controls in inverse order "away from the viewer". The child control order affects how docking uses available space and intersections between horizontal/vertical docked controls.

![Docking demonstration](/files/LcwhdfCuX4FJJAtftpJG)

Controls dock using the container's [`DisplayRectangle`](https://docs.wisej.com/api/wisej.web/general/control#displayrectangle) area, reduced by the [`Padding`](https://docs.wisej.com/api/wisej.web/general/control#padding) property.

{% hint style="warning" %}
The `DefaultLayout` engine doesn't use margins. To increase distance between docked controls, add docked [`Spacers`](https://docs.wisej.com/api/wisej.web/content/wisej.web.spacer).
{% endhint %}

#### Anchoring

Anchoring styles can be applied to any of the four sides of a control, or none.

When a control has no anchoring ([`AnchorStyles.None`](https://docs.wisej.com/api/wisej.web/enumerations/wisej.web.anchorstyles)), it will "float" within its container, preserving its relative location. Likewise, if anchoring is not set only for the vertical sides or horizontal sides, the control "floats" vertically or horizontally.

{% hint style="success" %}
To keep a control centered in its parent, center it and remove the anchoring.
{% endhint %}

The default initial value of the [`Anchor`](https://docs.wisej.com/api/wisej.web/general/control#anchor) property is `Top` + `Left`.

![Anchor demonstration](/files/xAgBOYpFgs5hVUzFC3Bv)

Padding and Margins are irrelevant to anchoring.

### Flow

The flow layout engine is implemented for the [`FlowLayoutPanel`](https://docs.wisej.com/api/wisej.web/containers/flowlayoutpanel). Child controls are arranged horizontally or vertically next to each other.

When using a `FlowLayoutPanel` in the designer, it extends all its children and adds several [extension properties](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.iextenderprovider) relevant only for flow layout:

* **`FillWeight`**: An arbitrary integer determining whether the child control grows horizontally or vertically (depending on [`FlowDirection`](https://docs.wisej.com/api/wisej.web/containers/flowlayoutpanel#flowdirection)) to use remaining space. Default is 0, preserving control size. ⚠️ When using `FillWeight`, set the control's [`MinimumSize`](https://docs.wisej.com/api/wisej.web/general/control#minimumsize) to prevent shrinking to 0.
* **`FlowBreak`**: When `true`, causes a flow break, wrapping to the next line/column depending on the panel's [`FlowDirection`](https://docs.wisej.com/api/wisej.web/containers/flowlayoutpanel/wisej.web.flowdirection).

{% hint style="info" %}
Set these values programmatically using `flowLayoutPanel.SetFlowBreak(child, value)` or `flowLayoutPanel.SetFillWeight(child, value)`.
{% endhint %}

In the animation below, green buttons have `FillWeight` set to 1. Left panel flows horizontally, right panel flows vertically:

![Flow layout demonstration](/files/Q2EEZrBqmxGE8fBVKkKk)

{% hint style="warning" %}
The `FlowLayout` engine enforces margins. Changing a child control's `Margin` property increases distance to adjacent controls.
{% endhint %}

### Table

The table layout engine is implemented for the [`TableLayoutPanel`](https://docs.wisej.com/api/wisej.web/containers/tablelayoutpanel). Child controls are arranged in cells in a grid.

When using the `TableLayoutPanel` in the designer, it extends its children and adds several [extension properties](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.iextenderprovider) relevant only for table layout:

* **`Row`, `Column`, `Cell`**: Determine the grid cell placement for the control. Only one control can occupy a specific cell.
* **`RowSpan`**: Determines how many rows are occupied by the cell.
* **`ColumnSpan`**: Determines how many columns are occupied by the cell.

This layout engine doesn't allow wrapping but supports growing. When adding a child programmatically, you can control whether to add a new row or column when all cells are assigned by setting the [`GrowStyle`](https://docs.wisej.com/api/wisej.web/containers/tablelayoutpanel#growstyle) property.

Use the [`RowStyles`](https://docs.wisej.com/api/wisej.web/containers/tablelayoutpanel#rowstyles) and [`ColumnStyles`](https://docs.wisej.com/api/wisej.web/containers/tablelayoutpanel#columnstyles) collections to determine cell sizing modes. Cells can:

* Resize proportionally using percentage
* Auto-size to fit content
* Have fixed pixel size

Additionally, controls can dock or anchor inside their assigned cell.

The animation below shows a `TableLayoutPanel` where `button3` spans 2 columns and is anchored left and right while vertically centered in the cell. Adding new controls using this code automatically adds new rows when the last row's cells are occupied:

```csharp
private void button1_Click(object sender, EventArgs e)
{
	this.tableLayoutPanel1.Controls.Add(new Button { 
		Text = "New Button"
	});
}
```

![Table layout demonstration](/files/6WA1ZjoPOwFKtxqi4dUx)

{% hint style="warning" %}
The `TableLayout` engine enforces margins. Changing a child control's `Margin` property affects distance to adjacent controls.
{% endhint %}

### Flex

The flex layout engine is implemented for the [`FlexLayoutPanel`](https://docs.wisej.com/api/wisej.web/containers/flexlayoutpanel). It comprises two layout engines: `HBoxLayout` and `VBoxLayout`. This container arranges its children horizontally or vertically, always filling the client area.

Controls can use `Margin`, [`MinimumSize`](https://docs.wisej.com/api/wisej.web/general/control#minimumsize), [`MaximumSize`](https://docs.wisej.com/api/wisej.web/general/control#maximumsize) and several extension properties to customize the layout:

* **`FillWeight`**: An arbitrary integer determining whether the child control grows horizontally or vertically (based on [`LayoutStyle`](https://docs.wisej.com/api/wisej.web/containers/flexlayoutpanel#layoutstyle)) to use remaining space. Default is 0, preserving control size. ⚠️ When using `FillWeight`, set the control's [`MinimumSize`](https://docs.wisej.com/api/wisej.web/general/control#minimumsize) to prevent shrinking to 0.
* **`AlignX`**: Controls horizontal alignment of child controls that can't fill a vertical `FlexLayoutPanel` due to width constraints. Overrides the default [`HorizontalAlign`](https://docs.wisej.com/api/wisej.web/containers/flexlayoutpanel#horizontalalign) for that control.
* **`AlignY`**: Controls vertical alignment of child controls that can't fill a horizontal `FlexLayoutPanel` due to height constraints. Overrides the default [`VerticalAlign`](https://docs.wisej.com/api/wisej.web/containers/flexlayoutpanel#verticalalign) for that control.

The animation below shows two `FlexLayoutPanel`s - first using HBox layout, second using VBox layout. Some buttons have `FillWeight` set to 1, and `button3` is set to align vertically:

![Flex layout demonstration](/files/WOGIyQDNFQVX81u2h4Cp)

{% hint style="warning" %}
The `FlexLayout` engine enforces margins. Changing a child control's `Margin` property affects distance to adjacent controls.
{% endhint %}

### Custom

You can build a custom layout engine by deriving from the `Wisej.Web.Layout.LayoutEngine` class and overriding the `Control.LayoutEngine` property in your container class.

You can create a single instance (singleton) of your layout engine to reuse, rather than creating a new instance for each container instantiation.

A layout engine needs to implement three methods:

* **`InitLayout(child, specifiedBounds)`**: Optional - can use base implementation. Since layout engines can be cached, this call refreshes any internal cache related to a child control.
* **`GetPreferredSize(container, proposedSize)`**: Optional - can use base implementation. Used when the container's `AutoSize` property is enabled and needs to measure children for preferred size.
* **`Layout(container, args)`**: Arranges child controls in their container. The simplest layout engine does nothing, letting controls use their own `Location` and `Size`.

This sample shows a basic custom layout that arranges child controls in a cascading pattern from top-left to bottom-right:

```csharp
public class CascadeLayout : LayoutEngine
{
	private static CascadeLayout _instance;

	private CascadeLayout() { }

	public static LayoutEngine Instance
		=> _instance = _instance ?? new CascadeLayout();

	public override bool Layout(object container, LayoutEventArgs layoutEventArgs)
	{
		var panel = (CascadeLayoutPanel)container;

		var gap = panel.Gap;
		var size = panel.ClientSize;
		var count = panel.Controls.Count;
		size.Width = size.Width - gap * (count - 1);
		size.Height = size.Height - gap * (count - 1);

		var i = 0;
		var bounds = new Rectangle(Point.Empty, size);
		foreach (Control child in panel.Controls)
		{
			child.Bounds = bounds;

			bounds.X += gap;
			bounds.Y += gap;
		}

		return false;
	}
}
```

The `CascadeLayout` engine works with this `CascadingLayoutPanel`. It adds a `Gap` property used by the layout engine:

```csharp
public class CascadeLayoutPanel : Panel
{
	public override LayoutEngine LayoutEngine 
		=> CascadeLayout.Instance;

	public int Gap
	{
		get { return _gap; }
		set
		{
			_gap = value;
			PerformLayout();
		}
	}
	private int _gap = 30;
}
```

Depending on the value of the Gap property and the size of the container, this is the result.

<div align="left"><img src="/files/LfIe6RSLO6kFENBWBIZX" alt=""></div>

## Design Time

### AutoLayout

<mark style="color:blue;background-color:green;">Since 3.0</mark>

The designer's toolbar has a new option to arrange child controls without setting the Dock or the Anchor properties.

<div align="left"><img src="/files/j6Eo9hrD4XXkdRx7CNuS" alt=""></div>

Clicking the AutoLayout button opens the AutoLayout floating panel:

<table><thead><tr><th width="218.01148338126245">Button</th><th width="422.066699443041">Description</th></tr></thead><tbody><tr><td><img src="/files/zfjLoQ4K8JQfUFftvVEA" alt=""></td><td>Arranges the controls horizontally, using the available space proportionally.</td></tr><tr><td><img src="/files/TXMAQv1NF4Qa8o740lie" alt="" data-size="original"></td><td>Arranges the controls vertically, using the available space proportionally.</td></tr><tr><td><img src="/files/GEo2TJq0xhZ4Y78YvVxS" alt=""></td><td>Docks the controls to the left of the containing area.</td></tr><tr><td><img src="/files/b7e3weDRe2lEwyQOw4ld" alt=""></td><td>Docks the controls to the right of the containing area.</td></tr><tr><td><img src="/files/5qpA7HBSJXAOzxl6Q9Aa" alt=""></td><td>Docks the controls to the bottom of the containing area.</td></tr><tr><td><img src="/files/yiYbd0NfPhZRvjj3Lmvn" alt=""></td><td>Docks the controls to the top of the containing area.</td></tr><tr><td><img src="/files/CyzxNpvKvIvzlthEx58k" alt=""></td><td>Resizes the controls to fill the containing area.</td></tr><tr><td><img src="/files/ZrJYY3WgPlNS92Nc8SZu" alt=""></td><td>Toggles using the controls' margin when applying the auto layout.</td></tr><tr><td><img src="/files/ji5qowTZJejErUbOlCJM" alt=""></td><td>Selects the horizontal alignment of the controls within the containing area.</td></tr><tr><td><img src="/files/FKuxeivZyi0HDZJu0Wze" alt=""></td><td>Selects the vertical alignment of the controls within the containing area.</td></tr><tr><td><img src="/files/uUZ4UGAH60NqkMx9WJCa" alt=""></td><td>Sets the spacing between the controls in pixels.</td></tr></tbody></table>

### Margins

Margins are used by the designer to create proximity snap lines.

When moving a control near another, proximity snap lines appear based on the controls' margins.

<div align="left"><img src="/files/lyOQhsEip1SFxiY0IYew" alt=""></div>

The vertical snap line between controls combines the top control's `Margin.Bottom` and bottom control's `Margin.Top` values. Using this feature correctly simplifies UI development and helps maintain UI/UX guidelines.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.wisej.com/docs/concepts/layouts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
