Skip to content
  •  
  •  
  •  
17 changes: 9 additions & 8 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ This is a **WinUI 3 / Windows App SDK** gallery app that demonstrates controls,

### Control pages

Each control demo lives in `Samples/ControlPages/` as a `[ControlName]Page.xaml` + `.xaml.cs` pair. Pages use the `ControlExample` custom control to show interactive demos:
Each control demo lives in its own folder under `Samples/{UniqueId}/` (e.g., `Samples/Button/`, `Samples/CheckBox/`). The folder name **must match** the control's `UniqueId` from `ControlInfoData.json` — this convention is used to generate GitHub source links and resolve sample code files at runtime. Each folder contains:

- `{ControlName}Page.xaml` + `.xaml.cs` — the control demo page
- `*.txt` — XAML/C# code snippets displayed in the gallery UI

Pages use the `ControlExample` custom control to show interactive demos:

```xml
<controls:ControlExample HeaderText="A basic button">
Expand All @@ -62,16 +67,12 @@ Each control demo lives in `Samples/ControlPages/` as a `[ControlName]Page.xaml`

`ControlExample` exposes: `Example`, `Output`, `Options`, `Xaml`/`XamlSource`, `CSharp`/`CSharpSource`, and `Substitutions` for dynamic `$(Key)` replacements in displayed code.

### Sample code files

`Samples/SampleCode/` contains `.txt` files with raw XAML/C# snippets displayed via `XamlSource`/`CSharpSource`. Naming: `{ControlName}Sample{N}_{xaml|cs|csharp}.txt`.

## Adding a New Control Page

1. Add the control entry to `Samples/Data/ControlInfoData.json` with a unique `UniqueId` matching the page class name (without `Page` suffix).
2. Create `Samples/ControlPages/[ControlName]Page.xaml` and `.xaml.cs` using the `ControlExample` pattern above.
1. Add the control entry to `SampleSupport/Data/ControlInfoData.json` with a unique `UniqueId` matching the page class name (without `Page` suffix).
2. Create a folder `Samples/{UniqueId}/` and add `{ControlName}Page.xaml` and `.xaml.cs` using the `ControlExample` pattern above. The folder name **must** match the `UniqueId` exactly.
3. The source generator auto-maps the `UniqueId` to the page type — no manual registration needed.
4. Add any external code snippets to `Samples/SampleCode/` as `.txt` files.
4. Add any code snippets as `.txt` files in the same `Samples/{UniqueId}/` folder. They are automatically included in the build via glob patterns in `ContentIncludes.props`.

## Accessibility

Expand Down
4 changes: 2 additions & 2 deletions WinUIGallery/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
<ResourceDictionary Source="ms-appx:///Styles/GridViewItem.xaml" />
<ResourceDictionary Source="ms-appx:///Styles/TextBlock.xaml" />
<ResourceDictionary Source="ms-appx:///Styles/SelectorBar.xaml" />
<ResourceDictionary Source="ms-appx:///Samples/ControlPages/Fundamentals/Controls/CounterControl.xaml" />
<ResourceDictionary Source="ms-appx:///Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.xaml" />
<ResourceDictionary Source="ms-appx:///Samples/CustomUserControls/CounterControl.xaml" />
<ResourceDictionary Source="ms-appx:///Samples/CustomUserControls/ValidatedPasswordBox.xaml" />
</ResourceDictionary.MergedDictionaries>

<ResourceDictionary.ThemeDictionaries>
Expand Down
320 changes: 14 additions & 306 deletions WinUIGallery/ContentIncludes.props

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion WinUIGallery/Helpers/IconsDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public async Task<List<IconData>> LoadIcons()
return icons;
}
}
var jsonText = await FileLoader.LoadText("SampleSupport/Data/IconsData.json");
var jsonText = await FileLoader.LoadText("Samples/Iconography/IconsData.json");
lock (_lock)
{
if (icons.Count == 0 &&
Expand Down
1 change: 0 additions & 1 deletion WinUIGallery/Models/ControlInfoData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public partial class ControlInfoDataGroup
public string Title { get; set; } = string.Empty;
public string IconGlyph { get; set; } = string.Empty;
public bool IsSpecialSection { get; set; }
public string Folder { get; set; } = string.Empty;
public ObservableCollection<ControlInfoDataItem> Items { get; set; } = [];

public override string ToString()
Expand Down
4 changes: 2 additions & 2 deletions WinUIGallery/Pages/ItemPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace WinUIGallery.Pages;
public sealed partial class ItemPage : Page
{
private static string WinUIBaseUrl = "https://github.com/microsoft/microsoft-ui-xaml/tree/main/src/controls/dev";
private static string GalleryBaseUrl = "https://github.com/microsoft/WinUI-Gallery/tree/main/WinUIGallery/Samples/ControlPages/";
private static string GalleryBaseUrl = "https://github.com/microsoft/WinUI-Gallery/tree/main/WinUIGallery/Samples/";

public ControlInfoDataItem? Item
{
Expand Down Expand Up @@ -70,7 +70,7 @@ protected override async void OnNavigatedTo(NavigationEventArgs e)
{
// Attach Navigated event to add RepositionThemeTransition after navigation
contentFrame.Navigated += ContentFrame_Navigated;
var pageName = string.IsNullOrEmpty(group.Folder) ? pageType.Name : $"{group.Folder}/{pageType.Name}";
var pageName = $"{item.UniqueId}/{pageType.Name}";
pageHeader.SetControlSourceLink(WinUIBaseUrl, item.SourcePath);
pageHeader.SetSamplePageSourceLinks(GalleryBaseUrl, pageName);
System.Diagnostics.Debug.WriteLine(string.Format("[ItemPage] Navigate to {0}", pageType.ToString()));
Expand Down
3 changes: 0 additions & 3 deletions WinUIGallery/SampleSupport/Data/ControlInfoData.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"UniqueId": "FundamentalsItem",
"Title": "Fundamentals",
"IsSpecialSection": true,
"Folder": "Fundamentals",
"Items": [
{
"UniqueId": "XamlResources",
Expand Down Expand Up @@ -203,7 +202,6 @@
"Title": "Design",
"IconGlyph": "",
"IsSpecialSection": true,
"Folder": "Design",
"Items": [
{
"UniqueId": "Color",
Expand Down Expand Up @@ -302,7 +300,6 @@
"UniqueId": "AccessibilityItem",
"Title": "Accessibility",
"IsSpecialSection": true,
"Folder": "Accessibility",
"Items": [
{
"UniqueId": "AccessibilityColorContrast",
Expand Down
4 changes: 0 additions & 4 deletions WinUIGallery/SampleSupport/Data/ControlInfoDataSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@
"description": "Indicates that this section is not a regular control section but is added to the navigation differently",
"default": true
},
"Folder": {
"type": "string",
"description": "Use to indicate a special child item for this folder. Only used when IsSpecialSection is true"
},
"Items": {
"type": "array",
"description": "Individual control info",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--- header
Description and help text: add descriptions and help text to controls
--- xaml
<StackPanel Spacing="8">
<!-- Use FullDescription to connect visible descriptions to their controls -->
<StackPanel Spacing="8">
<CheckBox Content="Clear cache on exit"
AutomationProperties.FullDescription="{x:Bind ClearCacheDescription.Text}" />
<TextBlock x:Name="ClearCacheDescription"
Text="Deletes all cached items when closing the browser. This includes cookies, images, and browsing history."
AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
</StackPanel>

<!-- Use HelpText and/or tooltips to explain nuances of controls -->
<Button Content="Cancel RSS subscriptions"
ToolTipService.ToolTip="Launch the cancellation wizard"
AutomationProperties.HelpText="Launch the cancellation wizard" />
</StackPanel>
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ AutomationProperties.Name="Contacts"&gt;
.</Paragraph>
</RichTextBlock>

<controls:ControlExample HeaderText="Description and help text: add descriptions and help text to controls">
<controls:ControlExample SampleDefinition="AccessibilityScreenReader\AccessibilityScreenReaderDescriptionHelpTextAdd.txt">
<controls:ControlExample.Example>
<StackPanel Spacing="8">
<!-- Use FullDescription to connect visible descriptions to their controls -->
Expand All @@ -304,29 +304,9 @@ AutomationProperties.Name="Contacts"&gt;
ToolTipService.ToolTip="Launch the cancellation wizard" />
</StackPanel>
</controls:ControlExample.Example>
<controls:ControlExample.Xaml>
<x:String xml:space="preserve">
&lt;StackPanel Spacing="8"&gt;
&lt;!-- Use FullDescription to connect visible descriptions to their controls --&gt;
&lt;StackPanel Spacing="8"&gt;
&lt;CheckBox Content="Clear cache on exit"
AutomationProperties.FullDescription="{x:Bind ClearCacheDescription.Text}" /&gt;
&lt;TextBlock x:Name="ClearCacheDescription"
Text="Deletes all cached items when closing the browser. This includes cookies, images, and browsing history."
AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" /&gt;
&lt;/StackPanel&gt;

&lt;!-- Use HelpText and/or tooltips to explain nuances of controls --&gt;
&lt;Button Content="Cancel RSS subscriptions"
ToolTipService.ToolTip="Launch the cancellation wizard"
AutomationProperties.HelpText="Launch the cancellation wizard" /&gt;
&lt;/StackPanel&gt;
</x:String>
</controls:ControlExample.Xaml>
</controls:ControlExample>

<controls:ControlExample HeaderText="Position in set: indicate the position of an element within a set">
<controls:ControlExample SampleDefinition="AccessibilityScreenReader\AccessibilityScreenReaderPositionIndicatePositionElement.txt">
<controls:ControlExample.Example>
<StackPanel>
<!-- Many controls automatically indicate position in set -->
Expand Down Expand Up @@ -364,42 +344,6 @@ AutomationProperties.Name="Contacts"&gt;
</StackPanel>
</StackPanel>
</controls:ControlExample.Example>
<controls:ControlExample.Xaml>
<x:String xml:space="preserve">
&lt;StackPanel&gt;
&lt;!-- Many controls automatically indicate position in set --&gt;
&lt;TextBlock Text="Students"
Style="{ThemeResource BodyStrongTextBlockStyle}"
x:Name="StudentsLabel"
AutomationProperties.AccessibilityView="Raw" /&gt;
&lt;ListView AutomationProperties.LabeledBy="{x:Bind StudentsLabel}"&gt;
&lt;ListView.ItemTemplate&gt;
&lt;DataTemplate x:DataType="x:String"&gt;
&lt;TextBlock Text="{x:Bind}" /&gt;
&lt;/DataTemplate&gt;
&lt;/ListView.ItemTemplate&gt;
&lt;x:String&gt;Nathan Quinn&lt;/x:String&gt;
&lt;x:String&gt;Jessica Lamber&lt;/x:String&gt;
&lt;x:String&gt;Carl Bond&lt;/x:String&gt;
&lt;x:String&gt;Jessica Russel&lt;/x:String&gt;
&lt;/ListView&gt;

&lt;!-- Custom layouts may need to specify PositionInSet and SizeOfSet manually. --&gt;
&lt;StackPanel Orientation="Horizontal"
Spacing="8"&gt;
&lt;Button AutomationProperties.PositionInSet="1"
AutomationProperties.SizeOfSet="3"
Content="View" /&gt;
&lt;Button AutomationProperties.PositionInSet="2"
AutomationProperties.SizeOfSet="3"
Content="Rename" /&gt;
&lt;Button AutomationProperties.PositionInSet="3"
AutomationProperties.SizeOfSet="3"
Content="Delete" /&gt;
&lt;/StackPanel&gt;
&lt;/StackPanel&gt;
</x:String>
</controls:ControlExample.Xaml>
</controls:ControlExample>

<!-- ***** Remove from visual tree sample ***** -->
Expand All @@ -423,7 +367,7 @@ AutomationProperties.Name="Contacts"&gt;
.</Paragraph>
</RichTextBlock>

<controls:ControlExample HeaderText="Remove a control from the content visual tree">
<controls:ControlExample SampleDefinition="AccessibilityScreenReader\AccessibilityScreenReaderRemoveControlContentVisual.txt">
<controls:ControlExample.Example>
<StackPanel Orientation="Horizontal">
<!--
Expand All @@ -448,18 +392,6 @@ AutomationProperties.Name="Contacts"&gt;
</TextBlock>
</StackPanel>
</controls:ControlExample.Example>
<controls:ControlExample.Xaml>
<x:String xml:space="preserve">
&lt;StackPanel Orientation="Horizontal"&gt;
&lt;!-- The image is not necessary for screen readers as it does not contain any information.
Thus we remove it from the content visual tree with AccessibilityView="Raw" --&gt;
&lt;Image Source="/Assets/SampleMedia/treetops.jpg" AutomationProperties.AccessibilityView="Raw" Height="40" VerticalAlignment="Top"/&gt;
&lt;TextBlock TextWrapping="WrapWholeWords" MaxWidth="400" Margin="8,0,0,0"&gt;This is some demo text.
The image on the left is just for decoration and serves no informational purpose.
To prevent Narrator or other screen readers from reading out the image, we set the accessibility view to "Raw" which removes it from the content visual tree.&lt;/TextBlock&gt;
&lt;/StackPanel&gt;
</x:String>
</controls:ControlExample.Xaml>
</controls:ControlExample>

<TextBlock
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--- header
Position in set: indicate the position of an element within a set
--- xaml
<StackPanel>
<!-- Many controls automatically indicate position in set -->
<TextBlock Text="Students"
Style="{ThemeResource BodyStrongTextBlockStyle}"
x:Name="StudentsLabel"
AutomationProperties.AccessibilityView="Raw" />
<ListView AutomationProperties.LabeledBy="{x:Bind StudentsLabel}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{x:Bind}" />
</DataTemplate>
</ListView.ItemTemplate>
<x:String>Nathan Quinn</x:String>
<x:String>Jessica Lamber</x:String>
<x:String>Carl Bond</x:String>
<x:String>Jessica Russel</x:String>
</ListView>

<!-- Custom layouts may need to specify PositionInSet and SizeOfSet manually. -->
<StackPanel Orientation="Horizontal"
Spacing="8">
<Button AutomationProperties.PositionInSet="1"
AutomationProperties.SizeOfSet="3"
Content="View" />
<Button AutomationProperties.PositionInSet="2"
AutomationProperties.SizeOfSet="3"
Content="Rename" />
<Button AutomationProperties.PositionInSet="3"
AutomationProperties.SizeOfSet="3"
Content="Delete" />
</StackPanel>
</StackPanel>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- header
Remove a control from the content visual tree
--- xaml
<StackPanel Orientation="Horizontal">
<!-- The image is not necessary for screen readers as it does not contain any information.
Thus we remove it from the content visual tree with AccessibilityView="Raw" -->
<Image Source="/Assets/SampleMedia/treetops.jpg" AutomationProperties.AccessibilityView="Raw" Height="40" VerticalAlignment="Top"/>
<TextBlock TextWrapping="WrapWholeWords" MaxWidth="400" Margin="8,0,0,0">This is some demo text.
The image on the left is just for decoration and serves no informational purpose.
To prevent Narrator or other screen readers from reading out the image, we set the accessibility view to "Raw" which removes it from the content visual tree.</TextBlock>
</StackPanel>
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
<Hyperlink Click="SystemBackdropLink_Click">SystemBackdrops (Mica/Acrylic)</Hyperlink> for background acrylic.
</Paragraph>
</RichTextBlock>
<controls:ControlExample x:Name="Example1" HeaderText="Default in-app acrylic brush.">
<controls:ControlExample x:Name="Example1" SampleDefinition="Acrylic\DefaultAppAcrylicBrush.txt">
<controls:ControlExample.Example>
<Grid
x:Name="Example1Grid"
Expand Down Expand Up @@ -74,13 +74,8 @@
<Rectangle Margin="12" Fill="{ThemeResource AcrylicInAppFillColorDefaultBrush}" />
</Grid>
</controls:ControlExample.Example>
<controls:ControlExample.Xaml>
<x:String>
&lt;Rectangle Fill="{ThemeResource AcrylicInAppFillColorDefaultBrush}" /&gt;
</x:String>
</controls:ControlExample.Xaml>
</controls:ControlExample>
<controls:ControlExample x:Name="Example3" HeaderText="Custom acrylic in-app brush.">
<controls:ControlExample x:Name="Example3" SampleDefinition="Acrylic\CustomAcrylicAppBrush.txt">
<controls:ControlExample.Example>
<Grid
x:Name="Example3Grid"
Expand Down Expand Up @@ -151,24 +146,14 @@
</ComboBox>
</StackPanel>
</controls:ControlExample.Options>
<controls:ControlExample.Xaml>
<x:String xml:space="preserve">
&lt;Rectangle Fill="{ThemeResource CustomAcrylicInAppBrush}" /&gt;

&lt;ResourceDictionary x:Key="Default"&gt;
&lt;media:AcrylicBrush x:Key="CustomAcrylicBrush"
TintOpacity="$(OpacitySlider)" TintColor="$(TintColor)" FallbackColor="$(FallbackColor)" /&gt;
&lt;/ResourceDictionary&gt;
</x:String>
</controls:ControlExample.Xaml>
<controls:ControlExample.Substitutions>
<controls:ControlExampleSubstitution Key="OpacitySlider" Value="{x:Bind OpacitySliderInApp.Value, Mode=OneWay}" />
<controls:ControlExampleSubstitution Key="TintColor" Value="{x:Bind ColorSelectorInApp.SelectedItem, Mode=OneWay}" />
<controls:ControlExampleSubstitution Key="FallbackColor" Value="{x:Bind FallbackColorSelectorInApp.SelectedItem, Mode=OneWay}" />
</controls:ControlExample.Substitutions>
</controls:ControlExample>

<controls:ControlExample x:Name="Example4" HeaderText="Luminosity with in-app Acrylic.">
<controls:ControlExample x:Name="Example4" SampleDefinition="Acrylic\LuminosityAppAcrylic.txt">
<controls:ControlExample.Example>
<Grid
x:Name="Example4Grid"
Expand Down Expand Up @@ -232,16 +217,6 @@
ValueChanged="LuminositySlider_ValueChanged" />
</StackPanel>
</controls:ControlExample.Options>
<controls:ControlExample.Xaml>
<x:String xml:space="preserve">
&lt;Rectangle Fill="{ThemeResource CustomAcrylicInAppLuminosity}" /&gt;

&lt;ResourceDictionary x:Key="Default"&gt;
&lt;media:AcrylicBrush x:Key="CustomAcrylicInAppLuminosity"
TintOpacity="$(OpacitySlider)" TintLuminosityOpacity="$(TintLuminositySlider)" TintColor="SkyBlue" FallbackColor="SkyBlue" /&gt;
&lt;/ResourceDictionary&gt;
</x:String>
</controls:ControlExample.Xaml>
<controls:ControlExample.Substitutions>
<controls:ControlExampleSubstitution Key="OpacitySlider" Value="{x:Bind OpacitySliderLumin.Value, Mode=OneWay}" />
<controls:ControlExampleSubstitution Key="TintLuminositySlider" Value="{x:Bind LuminositySlider.Value, Mode=OneWay}" />
Expand Down
9 changes: 9 additions & 0 deletions WinUIGallery/Samples/Acrylic/CustomAcrylicAppBrush.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--- header
Custom acrylic in-app brush.
--- xaml
<Rectangle Fill="{ThemeResource CustomAcrylicInAppBrush}" />

<ResourceDictionary x:Key="Default">
<media:AcrylicBrush x:Key="CustomAcrylicBrush"
TintOpacity="$(OpacitySlider)" TintColor="$(TintColor)" FallbackColor="$(FallbackColor)" />
</ResourceDictionary>
4 changes: 4 additions & 0 deletions WinUIGallery/Samples/Acrylic/DefaultAppAcrylicBrush.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--- header
Default in-app acrylic brush.
--- xaml
<Rectangle Fill="{ThemeResource AcrylicInAppFillColorDefaultBrush}" />
Loading