Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
99c07b3
StretchPanel initial commit
Avid29 Nov 29, 2025
e53c206
Basic StretchPanel implementation
Avid29 Nov 29, 2025
be5f590
Removed Wrap property
Avid29 Nov 29, 2025
c4b9ddc
Improved alignment behavior
Avid29 Nov 29, 2025
4966664
Merge branch 'CommunityToolkit:main' into StretchPanel
Avid29 Nov 29, 2025
dc2844e
Improved Sample to better display 600px vertical sample
Avid29 Nov 29, 2025
46703b9
Added FixedRowLengths property
Avid29 Nov 29, 2025
62b5e20
Added ForcedStretchMethod property and enum
Avid29 Nov 29, 2025
5c8a3d8
Fixed alignment issues for forced stretching
Avid29 Nov 29, 2025
a76e62f
Refactored Arrange to operate by rows
Avid29 Nov 30, 2025
379769c
Added Markdown Docs for the StretchPanel
Avid29 Nov 30, 2025
4977f87
Added OverflowBehaviors for StretchPanel
Avid29 Dec 1, 2025
a05b71d
Renamed to WrapPanel2
Avid29 Dec 3, 2025
f02d885
Ran XAML styles
Avid29 Dec 3, 2025
7716c08
Replaced Horizontal/Vertical Spacing with Item/Line spacing
Avid29 Dec 3, 2025
811bf3b
Merge branch 'main' into WrapPanel2
Avid29 Dec 9, 2025
8ccafec
Rennamed ForceStretchMethod ro StretchChildren
Avid29 Dec 9, 2025
c3d5658
Fixed missed rename in WrapPanel markdown docs
Avid29 Dec 9, 2025
f3fe793
Revised WrapPanel2 samples
Avid29 Dec 10, 2025
8d64ee6
Applied XAML styles
Avid29 Dec 10, 2025
d2408cb
Fixed FixedRowLength behavior
Avid29 Dec 10, 2025
349686c
Fixed ProportionalSample reference in Markdown docs
Avid29 Dec 10, 2025
63e1196
Fixed measuring issue causing FixedLengthRows with equally stretched …
Avid29 Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/WrapPanel2/OpenSolution.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@ECHO OFF

powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
Binary file added components/WrapPanel2/samples/Assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions components/WrapPanel2/samples/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
30 changes: 30 additions & 0 deletions components/WrapPanel2/samples/WrapPanel2.Samples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" Condition="Exists('$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))')" />

<PropertyGroup>
<ToolkitComponentName>WrapPanel2</ToolkitComponentName>
</PropertyGroup>

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
<ItemGroup>
<Compile Update="WrapPanel2BasicSample.xaml.cs">
<DependentUpon>WrapPanel2BasicSample.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="WrapPanel2ProportionalSample.xaml.cs">
<DependentUpon>WrapPanel2ProportionalSample.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Update="WrapPanel2MegaSample.xaml.cs">
<DependentUpon>WrapPanel2MegaSample.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Content Update="WrapPanel2BasicSample.xaml">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
</Project>
67 changes: 67 additions & 0 deletions components/WrapPanel2/samples/WrapPanel2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: WrapPanel2
author: Avid29
description: A labs-component candidate for a new WrapPanel implementation.
keywords: WrapPanel, Control, Layout
dev_langs:
- csharp
category: Layouts
subcategory: Panel
discussion-id: 762
issue-id: 763
icon: assets/icon.png
---

# WrapPanel2

The WrapPanel2 is an experiment for a new WrapPanel API using GridLength definitions to define the item's desired sizings.

When stretched along the main axis, the child elements with star-sized GridLength values will proportionally occupy the available space.

When not stretched along the main axis, star-sized child elements will be the smallest size possible while maintaining proportional sizing relative to each other and ensuring that all child elements are fully visible.


> [!Sample WrapPanel2BasicSample]

## Properties

### Fixed Row Length

When `FixedRowLengths` is enabled, all rows/columns will to stretch to the size of the largest row/column in the panel. When this is not enabled, rows/columns will size to their content individually.

### Stretching Children

The `StretchChildren` property allows you to specify how the panel should handle stretching in rows without star-sized definitions.

#### StarSizedOnly

When set to `StarSizedOnly`, this panel will never stretch rows/columns that do not have star-sized definitions. When the alignment is set to stretch, and even when fixed row lengths is enabled, the rows/columns without star-sized definitions will size to their content.

#### First

When set the `First`, this panel will stretch the first item in the row/column to occupy the remaining space when needed if `FixedRowLengths` is enabled.

#### Last

When set to `Last`, this panel will stretch the last item in the row/column to occupy the remaining space when needed if `FixedRowLengths` is enabled.

#### Equal

When set to `Equal`, this panel will stretch all items in the row/column to occupy the equal space throughout the row when needed if `FixedRowLengths` is enabled.

#### Proportional

When set to `Proportional`, this panel will stretch all items in the row/column proportionally to their defined size to occupy the remaining space when needed if `FixedRowLengths` is enabled.

## Additional Samples

### Adjusted Sizings Sample

> [!Sample WrapPanel2MegaSample]

### Proportional Sizing

Encoding diagram example

> [!Sample WrapPanel2ProportionalSample]

52 changes: 52 additions & 0 deletions components/WrapPanel2/samples/WrapPanel2BasicSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="WrapPanel2Experiment.Samples.WrapPanel2BasicSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:WrapPanel2Experiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
<Style TargetType="Border">
<Setter Property="Background" Value="#55000000" />
<Setter Property="BorderBrush" Value="#88000000" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
</Page.Resources>

<Grid MaxHeight="600"
Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
</Grid.RowDefinitions>

<StackPanel Margin="8"
Orientation="Horizontal"
Spacing="8">
<Button Click="AddItemClick"
Content="Add Item" />
<Button Click="Add5ItemsClick"
Content="Add 5 Items" />
<Button Click="ClearItemsClick"
Content="Clear" />
</StackPanel>

<controls:WrapPanel2 x:Name="WrapPanel"
Grid.Row="1"
HorizontalAlignment="{x:Bind LayoutHorizontalAlignment, Mode=OneWay}"
VerticalAlignment="{x:Bind LayoutVerticalAlignment, Mode=OneWay}"
FixedRowLengths="{x:Bind FixedRowLengths, Mode=OneWay}"
ItemSpacing="{x:Bind ItemSpacing, Mode=OneWay}"
LineSpacing="{x:Bind LineSpacing, Mode=OneWay}"
Orientation="{x:Bind local:WrapPanel2BasicSample.ConvertStringToOrientation(LayoutOrientation), Mode=OneWay}"
OverflowBehavior="{x:Bind local:WrapPanel2BasicSample.ConvertStringToOverflowBehavior(LayoutOverflowBehavior), Mode=OneWay}"
StretchChildren="{x:Bind local:WrapPanel2BasicSample.ConvertStringToForcedStretchMethod(LayoutStretchChildren), Mode=OneWay}" />
</Grid>
</Page>
115 changes: 115 additions & 0 deletions components/WrapPanel2/samples/WrapPanel2BasicSample.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using CommunityToolkit.WinUI.Controls;
using Windows.UI;

namespace WrapPanel2Experiment.Samples;

/// <summary>
/// An example sample page of a custom control inheriting from Panel.
/// </summary>
[ToolkitSampleMultiChoiceOption("LayoutOrientation", "Horizontal", "Vertical", Title = "Orientation")]
[ToolkitSampleMultiChoiceOption("LayoutHorizontalAlignment", "Left", "Center", "Right", "Stretch", Title = "Horizontal Alignment")]
[ToolkitSampleMultiChoiceOption("LayoutVerticalAlignment", "Top", "Center", "Bottom", "Stretch", Title = "Vertical Alignment")]
[ToolkitSampleNumericOption("ItemSpacing", 8, 0, 16, Title = "Item Spacing")]
[ToolkitSampleNumericOption("LineSpacing", 2, 0, 16, Title = "Line Spacing")]
[ToolkitSampleBoolOption("FixedRowLengths", false, Title = "Fixed Row Lengths")]
[ToolkitSampleMultiChoiceOption("LayoutStretchChildren", "StarSizedOnly", "First", "Last", "Equal", "Proportional", Title = "Forced Stretch Method")]
[ToolkitSampleMultiChoiceOption("LayoutOverflowBehavior", "Wrap", "Drop", Title = "Overflow Behavior")]

[ToolkitSample(id: nameof(WrapPanel2BasicSample), $"Basic demo of the {nameof(WrapPanel2)} with auto-sized items.", description: $"A sample showing every property of the {nameof(WrapPanel2)} panel.")]
public sealed partial class WrapPanel2BasicSample : Page
{
public WrapPanel2BasicSample()
{
this.InitializeComponent();
}

// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
public static Orientation ConvertStringToOrientation(string orientation) => orientation switch
{
"Vertical" => Orientation.Vertical,
"Horizontal" => Orientation.Horizontal,
_ => throw new System.NotImplementedException(),
};

// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
public static HorizontalAlignment ConvertStringToHorizontalAlignment(string alignment) => alignment switch
{
"Left" => HorizontalAlignment.Left,
"Center" => HorizontalAlignment.Center,
"Right" => HorizontalAlignment.Right,
"Stretch" => HorizontalAlignment.Stretch,
_ => throw new System.NotImplementedException(),
};

// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
public static VerticalAlignment ConvertStringToVerticalAlignment(string alignment) => alignment switch
{
"Top" => VerticalAlignment.Top,
"Center" => VerticalAlignment.Center,
"Bottom" => VerticalAlignment.Bottom,
"Stretch" => VerticalAlignment.Stretch,
_ => throw new System.NotImplementedException(),
};

// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
public static StretchChildren ConvertStringToForcedStretchMethod(string stretchMethod) => stretchMethod switch
{
"StarSizedOnly" => StretchChildren.StarSizedOnly,
"First" => StretchChildren.First,
"Last" => StretchChildren.Last,
"Equal" => StretchChildren.Equal,
"Proportional" => StretchChildren.Proportional,
_ => throw new System.NotImplementedException(),
};

// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
public static OverflowBehavior ConvertStringToOverflowBehavior(string overflowBehavior) => overflowBehavior switch
{
"Wrap" => OverflowBehavior.Wrap,
"Drop" => OverflowBehavior.Drop,
_ => throw new System.NotImplementedException(),
};

private int _index;

private string[] LoremIpsumWords => LoremIpsum.Split(' ');

private string LoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam fermentum placerat pretium. Phasellus molestie faucibus purus ut semper. Etiam felis ante, condimentum sed leo in, aliquam pharetra libero. Etiam ante ante, sagittis in semper eu, aliquam non sapien. Donec a pharetra magna. Suspendisse et nulla magna. Cras varius sem dolor, ac faucibus turpis malesuada ac. Maecenas rutrum tortor et faucibus rutrum. Vestibulum in gravida odio, non dapibus dui. Praesent leo tellus, vulputate sed sollicitudin id, fringilla quis ligula. Cras eget ex vitae purus pulvinar mattis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec consectetur tellus id augue ultrices, eget congue tellus pharetra.";

private void AddItemClick(object sender, RoutedEventArgs e)
{
AddItem();
}

private void Add5ItemsClick(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 5; i++)
AddItem();
}

private void ClearItemsClick(object sender, RoutedEventArgs e)
{
WrapPanel.Children.Clear();
_index = 0;
}

private void AddItem()
{
_index = _index % LoremIpsumWords.Length;

var currentWord = LoremIpsumWords[_index++];
var border = new Border()
{
Child = new TextBlock()
{
Text = currentWord,
}
};

WrapPanel.Children.Add(border);
}
}
83 changes: 83 additions & 0 deletions components/WrapPanel2/samples/WrapPanel2MegaSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="WrapPanel2Experiment.Samples.WrapPanel2MegaSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:WrapPanel2Experiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Page.Resources>
<Style TargetType="Border">
<Setter Property="Background" Value="#55000000" />
<Setter Property="BorderBrush" Value="#88000000" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="8" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
</Style>
</Page.Resources>

<Grid MaxHeight="600"
Margin="16">
<controls:WrapPanel2 HorizontalAlignment="{x:Bind LayoutHorizontalAlignment, Mode=OneWay}"
VerticalAlignment="{x:Bind LayoutVerticalAlignment, Mode=OneWay}"
FixedRowLengths="{x:Bind FixedRowLengths, Mode=OneWay}"
ItemSpacing="{x:Bind ItemSpacing, Mode=OneWay}"
LineSpacing="{x:Bind LineSpacing, Mode=OneWay}"
Orientation="{x:Bind local:WrapPanel2MegaSample.ConvertStringToOrientation(LayoutOrientation), Mode=OneWay}"
OverflowBehavior="{x:Bind local:WrapPanel2MegaSample.ConvertStringToOverflowBehavior(LayoutOverflowBehavior), Mode=OneWay}"
StretchChildren="{x:Bind local:WrapPanel2MegaSample.ConvertStringToForcedStretchMethod(LayoutStretchChildren), Mode=OneWay}">
<Border controls:WrapPanel2.LayoutLength="2*">
<TextBlock HorizontalAlignment="Center"
Text="2*" />
</Border>
<Border controls:WrapPanel2.LayoutLength="Auto">
<TextBlock HorizontalAlignment="Center"
Text="Auto" />
</Border>
<Border controls:WrapPanel2.LayoutLength="400">
<TextBlock HorizontalAlignment="Center"
Text="400px" />
</Border>
<Border controls:WrapPanel2.LayoutLength="1*">
<TextBlock HorizontalAlignment="Center"
Text="1*" />
</Border>
<Border controls:WrapPanel2.LayoutLength="200">
<TextBlock HorizontalAlignment="Center"
Text="200px" />
</Border>
<Border controls:WrapPanel2.LayoutLength="300">
<TextBlock HorizontalAlignment="Center"
Text="300px" />
</Border>
<Border controls:WrapPanel2.LayoutLength="600">
<TextBlock HorizontalAlignment="Center"
Text="600px" />
</Border>
<Border controls:WrapPanel2.LayoutLength="2*">
<TextBlock HorizontalAlignment="Center"
Text="2*" />
</Border>
<Border controls:WrapPanel2.LayoutLength="1.5*">
<TextBlock HorizontalAlignment="Center"
Text="1.5*" />
</Border>
<Border controls:WrapPanel2.LayoutLength="Auto">
<TextBlock HorizontalAlignment="Center"
Text="Auto with longer text" />
</Border>
<Border controls:WrapPanel2.LayoutLength="400">
<TextBlock HorizontalAlignment="Center"
Text="400px" />
</Border>
<Border controls:WrapPanel2.LayoutLength="1*">
<TextBlock HorizontalAlignment="Center"
Text="1*" />
</Border>
</controls:WrapPanel2>
</Grid>
</Page>
Loading
Loading