Skip to content

Commit 5788dee

Browse files
Add WrapPanel API Spec based on Windows Community Toolkit (WCT) (#10858)
* Add WrapPanel API Spec based on Windows Community Toolkit (WCT) control for Public Review * Apply all IDL comments for API details from initial review before API review meeting * Update specs/WCT/Primitives/WrapPanel.md Co-authored-by: neerajmsgithub <[email protected]> * WrapPanel Spec - Address comment about natural/minimal sizing with comment about Grid Auto * [Spec] WrapPanel API Review - Rename StretchChild to StretchChildren Added additional note about review commentary for future. * [Spec] WrapPanel - Add extra example image of varying sized elements * [Spec] WrapPanel update from Horizontal/VerticalSpacing to Item/LineSpacing * Address PR Review comments on LTR and Items/LineSpacing descriptions/examples * Update StretchChildren to ItemsStretch to align to UniformGridLayout, also expand enum name to be specific to the Panel, as other panels do. --------- Co-authored-by: neerajmsgithub <[email protected]>
1 parent c1a2f46 commit 5788dee

File tree

8 files changed

+243
-0
lines changed

8 files changed

+243
-0
lines changed

specs/WCT/Primitives/WrapPanel.md

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
<!-- From: https://github.com/microsoft/WindowsAppSDK/blob/main/specs/spec_template.md -->
2+
3+
<!-- TEMPLATE
4+
Style guide:
5+
* Use second person; speak to the developer who will be learning/using this API.
6+
(For example "you use this to..." rather than "the developer uses this to...")
7+
* Use hard returns to keep the page width within ~100 columns.
8+
(Otherwise it's more difficult to leave comments in a GitHub PR.)
9+
* Talk about an API's behavior, not its implementation.
10+
(Speak to the developer using this API, not to the team implementing it.)
11+
* A picture is worth a thousand words.
12+
* An example is worth a million words.
13+
* Keep examples realistic but simple; don't add unrelated complications.
14+
(An example that passes a stream needn't show the process of launching the File-Open dialog.)
15+
-->
16+
17+
WrapPanel
18+
===
19+
20+
# Background
21+
22+
_This spec brings WrapPanel from the Windows Community Toolkit (as WPF Polyfill) to WinUI._
23+
24+
WrapPanel has been a staple of XAML development since its inception, originally included in WPF
25+
[WrapPanel](https://learn.microsoft.com/dotnet/desktop/wpf/controls/wrappanel). It was originally added
26+
to the Windows Community Toolkit (WCT) in v1.3 on 2/10/2017
27+
([see WCT history here](https://github.com/CommunityToolkit/Windows/discussions/722)) and used in a
28+
multitude of applications since.
29+
30+
`WrapPanel` is a simple and versatile panel that positions child controls vertically or horizontally
31+
based on the orientation in sequence and when max width / max height is reached a new virtual row (in
32+
case of horizontal) or column (in case of vertical) is automatically created to fit new controls.
33+
34+
This differs importantly from `StackPanel` where all children must be in a single row/column and aids in
35+
responsive UI flow.
36+
37+
> [!IMPORTANT]
38+
> About WPF Compatibility: This spec aligns to the WCT implementation for compatibility for existing
39+
WinUI users. WrapPanel in the WCT was modernized and updated as part of general Panel modernization for
40+
responsive layouts done for UWP and simplified for developer's ease-of-use. It is the goal to bring this
41+
to WinUI for this same fundamental experience and allow easy migration from WCT developers and existing
42+
usage in WinUI apps vs. direct migration for WPF developers.
43+
44+
Reference Docs:
45+
- [WCT WrapPanel Conceptual](https://learn.microsoft.com/dotnet/communitytoolkit/windows/primitives/wrappanel)
46+
- [WCT WrapPanel API](https://learn.microsoft.com/dotnet/api/communitytoolkit.winui.controls.wrappanel)
47+
- [WinUI StackPanel Conceptual](https://learn.microsoft.com/windows/apps/design/layout/layout-panels#stackpanel)
48+
- [WinUI StackPanel API Comparison](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stackpanel)
49+
- [WPF WrapPanel Conceptual](https://learn.microsoft.com/dotnet/desktop/wpf/controls/wrappanel)
50+
- [WPF WrapPanel API](https://learn.microsoft.com/dotnet/api/system.windows.controls.wrappanel)
51+
- [WPF StackPanel API Comparison](https://learn.microsoft.com/dotnet/api/system.windows.controls.stackpanel)
52+
- Item/LineSpacing Naming:
53+
- [LinedFlowLayout Class API](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.linedflowlayout)
54+
- [Avalonia WrapPanel PR](https://github.com/AvaloniaUI/Avalonia/pull/18079)
55+
56+
57+
# Conceptual pages (How To)
58+
59+
<!-- _(This is conceptual documentation that will go to docs.microsoft.com "how to" page)_ -->
60+
61+
<!-- See: https://learn.microsoft.com/windows/apps/design/layout/layout-panels -->
62+
63+
The WrapPanel is a layout panel that arranges child elements in a sequential position from left to right (based on [`FlowDirection`](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.flowdirection)),
64+
items overflowing the line will break to the next line automatically at the edge of the containing panel.
65+
66+
You can set the `Orientation` property to specify the direction of child elements. The default
67+
orientation is **Horizontal**.
68+
69+
The following XAML shows how to create a WrapPanel of items:
70+
71+
```xml
72+
<WrapPanel Width="132">
73+
<Rectangle Fill="Red" Width="44" Height="44"/>
74+
<Rectangle Fill="Blue" Width="44" Height="44"/>
75+
<Rectangle Fill="Green" Width="44" Height="44"/>
76+
<Rectangle Fill="Orange" Width="44" Height="44"/>
77+
</WrapPanel>
78+
```
79+
80+
The result looks like this:
81+
82+
![WrapPanel example layout](images/layout-panel-wrap-panel.png)
83+
84+
In a WrapPanel, if a child element's size is not set explicitly, it will be given the minimal/natural
85+
amount of space for layout, like the "Auto" size of a Grid's Row or ColumnDefinition. In the example
86+
above, the size of the rectangles are explicitly set, if the **Width** or **Height** were not provided,
87+
the rectangle would not appear (as it would be given a **0** size in either dimension). This is a key
88+
contrast to a standard `StackPanel` control in terms of default behavior.
89+
90+
# API Pages
91+
92+
<!-- _(Each of the following L2 sections correspond to a page that will be on docs.microsoft.com)_ -->
93+
94+
## WrapPanel class
95+
96+
The WrapPanel is a layout panel that arranges child elements in a sequential position from left to right,
97+
items overflowing the line will break to the next line automatically at the edge of the containing panel.
98+
99+
![WrapPanel example layout](images/WrapPanel.png)
100+
101+
By default, WrapPanel stacks items from left to right in the order they are declared. You can set the
102+
`Orientation` property to **Vertical** to stack items from top to bottom instead, overflowing to the
103+
right.
104+
105+
Spacing can be automatically added between items using the `ItemSpacing` and `LineSpacing`
106+
properties. When the `Orientation` is **Horizontal**, `ItemSpacing` adds uniform horizontal spacing
107+
between each individual item, and `LineSpacing` adds uniform spacing between each row of items.
108+
109+
When the `Orientation` is **Vertical**, `LineSpacing` adds uniform spacing between each column of
110+
items, and `ItemSpacing` adds uniform vertical spacing between individual items.
111+
112+
The following example image shows another example of `WrapPanel` usage where elements may be of varying sizes:
113+
114+
![WrapPanel alternate example layout](images/WrapPanelVaryingSizesExample.png)
115+
116+
## WrapPanel.ItemSpacing property
117+
118+
Gets or sets a uniform distance between items. If Orientation is Horizontal, then this is the horizontal
119+
distance between items on a single row. If Orientation is Vertical, then this is the vertical distance between
120+
items in a single column. Defaults to 0.
121+
122+
In the following example, ItemSpacing has been added to space out items, though in this case that
123+
then wraps the Green box around to the next line due to the Width constraint on the WrapPanel:
124+
125+
```xml
126+
<controls:WrapPanel Width="132" ItemSpacing="16">
127+
<Rectangle Fill="Red" Width="44" Height="44"/>
128+
<Rectangle Fill="Blue" Width="44" Height="44"/>
129+
<Rectangle Fill="Green" Width="44" Height="44"/>
130+
<Rectangle Fill="Orange" Width="44" Height="44"/>
131+
</controls:WrapPanel>
132+
```
133+
134+
The result looks like this:
135+
136+
![WrapPanel ItemSpacing example](images/WrapPanelItemSpacing.png)
137+
138+
## WrapPanel.LineSpacing property
139+
140+
Gets or sets a uniform distance between lines. If Orientation is Horizontal, then this is the vertical
141+
distance between items on a single row. If Orientation is Vertical, then this is the horizontal distance between
142+
items in a single column. Defaults to 0.
143+
144+
In the following example, LineSpacing has been added to space out the rows:
145+
146+
```xml
147+
<controls:WrapPanel Width="132" LineSpacing="16">
148+
<Rectangle Fill="Red" Width="44" Height="44"/>
149+
<Rectangle Fill="Blue" Width="44" Height="44"/>
150+
<Rectangle Fill="Green" Width="44" Height="44"/>
151+
<Rectangle Fill="Orange" Width="44" Height="44"/>
152+
</controls:WrapPanel>
153+
```
154+
155+
The result looks like this:
156+
157+
![WrapPanel ItemSpacing example](images/WrapPanelLineSpacing.png)
158+
159+
## WrapPanel.Orientation property
160+
161+
Gets or sets the orientation of the WrapPanel. **Horizontal** means that child controls will be added
162+
horizontally until the width of the panel is reached, then a new row is added to add new child controls.
163+
**Vertical** means that children will be added vertically until the height of the panel is reached, then
164+
a new column is added. Default is **Horizontal**.
165+
166+
## WrapPanel.Padding property
167+
168+
Gets or sets the distance between the border and its child object.
169+
170+
## WrapPanel.ItemsStretch property
171+
172+
Gets or sets a value that indicates how items are sized to fill the available space. When set to **Last**,
173+
the final child can stretch and be given all the rest of the available space for the row (when Orientation is
174+
**Horizontal**) or column (when Orientation is **Vertical**). Defaults to **None** where no changes to
175+
default behavior layout are provided and items retain their natural size.
176+
177+
In the following example, the last Orange rectangle will be constrained and pushed to the 2nd row.
178+
Normally if given the same Width/Height as the others, it'd sit just below the Red rectangle to the left.
179+
Instead, we can remove it's Width and have it fill the rest of the row by setting `ItemsStretch` to **Last**:
180+
181+
```xml
182+
<controls:WrapPanel Width="132" ItemsStretch="Last">
183+
<Rectangle Fill="Red" Width="44" Height="44"/>
184+
<Rectangle Fill="Blue" Width="44" Height="44"/>
185+
<Rectangle Fill="Green" Width="44" Height="44"/>
186+
<Rectangle Fill="Orange" Height="44" />
187+
</controls:WrapPanel>
188+
```
189+
190+
The result looks like this:
191+
192+
![WrapPanel ItemsStretch example](images/WrapPanelItemsStretch.png)
193+
194+
# API Details
195+
196+
```c# (but really MIDL3)
197+
[contract(Microsoft.UI.Xaml.WinUIContract, )]
198+
[webhosthidden]
199+
namespace Microsoft.UI.Xaml.Controls
200+
{
201+
unsealed runtimeclass WrapPanel
202+
: Microsoft.UI.Xaml.Controls.Panel
203+
{
204+
[method_name("CreateInstance")] WrapPanel();
205+
206+
Double ItemSpacing;
207+
Double LineSpacing;
208+
Orientation Orientation;
209+
Thickness Padding;
210+
WrapPanelItemStretch ItemsStretch;
211+
212+
static Microsoft.UI.Xaml.DependencyProperty ItemSpacingProperty { get; };
213+
static Microsoft.UI.Xaml.DependencyProperty LineSpacingProperty { get; };
214+
static Microsoft.UI.Xaml.DependencyProperty OrientationProperty { get; };
215+
static Microsoft.UI.Xaml.DependencyProperty PaddingProperty { get; };
216+
static Microsoft.UI.Xaml.DependencyProperty ItemsStretchProperty { get; };
217+
}
218+
219+
enum WrapPanelItemsStretch
220+
{
221+
None = 0,
222+
Last
223+
}
224+
}
225+
```
226+
227+
# Appendix
228+
229+
<!-- TEMPLATE
230+
Anything else that you want to write down about implementation notes and for posterity,
231+
but that isn't necessary to understand the purpose and usage of the API.
232+
233+
This or the Background section are a good place to describe alternative designs
234+
and why they were rejected.
235+
-->
236+
237+
API Review Note: Renamed `StretchChild` to `ItemsStretch` to better describe action on items (children) of
238+
panel, as well as leave more room for additional flags/modes in the future (Equal, Proportional, etc...).
239+
240+
API Review Note: Aligned to `ItemSpacing` and `LineSpacing` for better clarity across
241+
`Orientation` changed based on discussion from Avalonia review and new precedence in
242+
Windows App SDK from `LinedFlowLayout`. Discussed that experimental [`FlowLayout`](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.flowlayout) class
243+
should also be updated to align.
676 Bytes
Loading
468 Bytes
Loading
455 Bytes
Loading
517 Bytes
Loading
7.98 KB
Loading
13.8 KB
Loading
483 Bytes
Loading

0 commit comments

Comments
 (0)