diff --git a/WinUIGallery/App.xaml.cs b/WinUIGallery/App.xaml.cs
index ff37e96ce..6faf0081c 100644
--- a/WinUIGallery/App.xaml.cs
+++ b/WinUIGallery/App.xaml.cs
@@ -140,6 +140,24 @@ private async void EnsureWindow()
targetPageType = typeof(ItemPage);
}
}
+ // Handle JumpList launch arguments (passed as command-line args)
+ else if (eventArgs != null &&
+ eventArgs.Kind == ExtendedActivationKind.Launch &&
+ eventArgs.Data is ILaunchActivatedEventArgs launchArgs &&
+ !string.IsNullOrEmpty(launchArgs.Arguments))
+ {
+ string arg = launchArgs.Arguments.Trim();
+ targetPageArguments = arg;
+
+ if (ControlInfoDataSource.Instance.Groups.Any(g => g.UniqueId == arg))
+ {
+ targetPageType = typeof(SectionPage);
+ }
+ else if (ControlInfoDataSource.Instance.Groups.Any(g => g.Items.Any(i => i.UniqueId == arg)))
+ {
+ targetPageType = typeof(ItemPage);
+ }
+ }
MainWindow.Navigate(targetPageType, targetPageArguments);
@@ -149,6 +167,9 @@ private async void EnsureWindow()
navItem.IsSelected = true;
}
+ // Initialize the taskbar JumpList with fixed tasks and favorites.
+ await JumpListHelper.UpdateJumpListAsync();
+
// Activate the startup window.
MainWindow.Activate();
}
diff --git a/WinUIGallery/Assets/ControlImages/JumpList.png b/WinUIGallery/Assets/ControlImages/JumpList.png
new file mode 100644
index 000000000..6fdc534a6
Binary files /dev/null and b/WinUIGallery/Assets/ControlImages/JumpList.png differ
diff --git a/WinUIGallery/Controls/PageHeader.xaml b/WinUIGallery/Controls/PageHeader.xaml
index 705d3e193..654af6aa6 100644
--- a/WinUIGallery/Controls/PageHeader.xaml
+++ b/WinUIGallery/Controls/PageHeader.xaml
@@ -7,9 +7,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:models="using:WinUIGallery.Models"
xmlns:local="using:WinUIGallery.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:models="using:WinUIGallery.Models"
Loaded="UserControl_Loaded"
mc:Ignorable="d">
@@ -34,11 +34,11 @@
+ TextWrapping="NoWrap" />
-
+
-
+
-
+
diff --git a/WinUIGallery/Controls/PageHeader.xaml.cs b/WinUIGallery/Controls/PageHeader.xaml.cs
index 57297eb7d..ff22544da 100644
--- a/WinUIGallery/Controls/PageHeader.xaml.cs
+++ b/WinUIGallery/Controls/PageHeader.xaml.cs
@@ -53,11 +53,13 @@ public void SetControlSourceLink(string BaseUri, string SourceLink)
if (!string.IsNullOrEmpty(SourceLink))
{
ControlSourcePanel.Visibility = Visibility.Visible;
+ ControlSourceSeparator.Visibility = Visibility.Visible;
ControlSourceLink.NavigateUri = new Uri(BaseUri + SourceLink);
}
else
{
ControlSourcePanel.Visibility = Visibility.Collapsed;
+ ControlSourceSeparator.Visibility = Visibility.Collapsed;
}
}
diff --git a/WinUIGallery/Helpers/JumpListHelper.cs b/WinUIGallery/Helpers/JumpListHelper.cs
new file mode 100644
index 000000000..6daaca17f
--- /dev/null
+++ b/WinUIGallery/Helpers/JumpListHelper.cs
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Windows.UI.StartScreen;
+using WinUIGallery.Models;
+
+namespace WinUIGallery.Helpers;
+
+///
+/// Manages the app's taskbar JumpList, providing quick access to
+/// recently visited items and user-favorited items.
+///
+internal static class JumpListHelper
+{
+ ///
+ /// Rebuilds the JumpList with recently visited items and the current set of favorite items.
+ /// Safe to call at any time; silently returns if JumpList is not supported.
+ ///
+ public static async Task UpdateJumpListAsync()
+ {
+ if (!NativeMethods.IsAppPackaged || !JumpList.IsSupported())
+ {
+ return;
+ }
+
+ try
+ {
+ JumpList jumpList = await JumpList.LoadCurrentAsync();
+ jumpList.Items.Clear();
+ jumpList.SystemGroupKind = JumpListSystemGroupKind.None;
+
+ // Dynamic group: Recent
+ var recentlyVisited = SettingsHelper.Current.RecentlyVisited;
+ foreach (string uniqueId in recentlyVisited)
+ {
+ AddItemTask(jumpList, uniqueId, groupName: "Recent");
+ }
+
+ // Dynamic group: Favorites
+ var favorites = SettingsHelper.Current.Favorites;
+ foreach (string uniqueId in favorites)
+ {
+ AddItemTask(jumpList, uniqueId, groupName: "Favorites");
+ }
+
+ await jumpList.SaveAsync();
+ }
+ catch
+ {
+ // JumpList updates are best-effort; don't crash the app.
+ }
+ }
+
+ private static void AddItemTask(JumpList jumpList, string uniqueId, string groupName)
+ {
+ ControlInfoDataItem? item = ControlInfoDataSource.Instance.Groups
+ .SelectMany(g => g.Items)
+ .FirstOrDefault(i => i.UniqueId == uniqueId);
+
+ if (item == null)
+ {
+ return;
+ }
+
+ JumpListItem task = JumpListItem.CreateWithArguments(uniqueId, item.Title);
+ task.GroupName = groupName;
+ task.Description = "Go to " + item.Title;
+ task.Logo = new Uri(item.ImagePath);
+ jumpList.Items.Add(task);
+ }
+}
\ No newline at end of file
diff --git a/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs b/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs
index 7e432895e..abb8b8a40 100644
--- a/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs
+++ b/WinUIGallery/Helpers/SettingsHelper/SettingsHelper.cs
@@ -56,11 +56,13 @@ public void UpdateFavorites(Action> updater)
var list = Favorites;
updater(list);
Favorites = list;
+ _ = JumpListHelper.UpdateJumpListAsync();
}
public void UpdateRecentlyVisited(Action> updater)
{
var list = RecentlyVisited;
updater(list);
RecentlyVisited = list;
+ _ = JumpListHelper.UpdateJumpListAsync();
}
}
diff --git a/WinUIGallery/Samples/ControlPages/JumpListPage.xaml b/WinUIGallery/Samples/ControlPages/JumpListPage.xaml
new file mode 100644
index 000000000..b4fa0b4d9
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/JumpListPage.xaml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var jumpList = await JumpList.LoadCurrentAsync();
+
+var task = JumpListItem.CreateWithArguments("/compose", "New Message");
+task.Description = "Compose a new message";
+task.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+jumpList.Items.Add(task);
+await jumpList.SaveAsync();
+
+
+
+
+
+
+
+
+
+
+
+var jumpList = await JumpList.LoadCurrentAsync();
+
+var item = JumpListItem.CreateWithArguments("/project-alpha", "Project Alpha");
+item.GroupName = "Projects";
+item.Description = "Open Project Alpha";
+item.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+jumpList.Items.Add(item);
+await jumpList.SaveAsync();
+
+
+
+
+
\ No newline at end of file
diff --git a/WinUIGallery/Samples/ControlPages/JumpListPage.xaml.cs b/WinUIGallery/Samples/ControlPages/JumpListPage.xaml.cs
new file mode 100644
index 000000000..fab23a33f
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/JumpListPage.xaml.cs
@@ -0,0 +1,78 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using System;
+using Windows.UI.StartScreen;
+using WinUIGallery.Helpers;
+
+namespace WinUIGallery.ControlPages;
+
+public sealed partial class JumpListPage : Page
+{
+ public JumpListPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private async void AddTasksButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!NativeMethods.IsAppPackaged)
+ {
+ return;
+ }
+
+ JumpList jumpList = await JumpList.LoadCurrentAsync();
+
+ JumpListItem composeTask = JumpListItem.CreateWithArguments("/compose", "New Message");
+ composeTask.Description = "Compose a new message";
+ composeTask.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+ JumpListItem searchTask = JumpListItem.CreateWithArguments("/search", "Search");
+ searchTask.Description = "Search for items";
+ searchTask.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+ jumpList.Items.Add(composeTask);
+ jumpList.Items.Add(searchTask);
+
+ await jumpList.SaveAsync();
+ }
+
+ private async void ClearTasksButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!NativeMethods.IsAppPackaged)
+ {
+ return;
+ }
+
+ JumpList jumpList = await JumpList.LoadCurrentAsync();
+ jumpList.Items.Clear();
+ await jumpList.SaveAsync();
+ }
+
+ private async void AddCustomGroupButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!NativeMethods.IsAppPackaged)
+ {
+ return;
+ }
+
+ JumpList jumpList = await JumpList.LoadCurrentAsync();
+
+ JumpListItem item1 = JumpListItem.CreateWithArguments("/project-alpha", "Project Alpha");
+ item1.GroupName = "Projects";
+ item1.Description = "Open Project Alpha";
+ item1.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+ JumpListItem item2 = JumpListItem.CreateWithArguments("/project-beta", "Project Beta");
+ item2.GroupName = "Projects";
+ item2.Description = "Open Project Beta";
+ item2.Logo = new Uri("ms-appx:///Assets/Tiles/AppList.targetsize-48.png");
+
+ jumpList.Items.Add(item1);
+ jumpList.Items.Add(item2);
+
+ await jumpList.SaveAsync();
+ }
+}
\ No newline at end of file
diff --git a/WinUIGallery/Samples/Data/ControlInfoData.json b/WinUIGallery/Samples/Data/ControlInfoData.json
index 5e8b63213..1d2be168f 100644
--- a/WinUIGallery/Samples/Data/ControlInfoData.json
+++ b/WinUIGallery/Samples/Data/ControlInfoData.json
@@ -3112,6 +3112,68 @@
"UniqueId": "System",
"Title": "System",
"IconGlyph": "",
+ "Items": [
+ {
+ "UniqueId": "Clipboard",
+ "Title": "Clipboard",
+ "ApiNamespace": "Windows.ApplicationModel.DataTransfer",
+ "Subtitle": "Copy and paste to and from the system Clipboard.",
+ "ImagePath": "ms-appx:///Assets/ControlImages/Clipboard.png",
+ "Description": "Copy and paste to and from the system Clipboard.",
+ "Docs": [
+ {
+ "Title": "Clipboard - API",
+ "Uri": "https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"
+ }
+ ]
+ },
+ {
+ "UniqueId": "ContentIsland",
+ "Title": "ContentIsland",
+ "ApiNamespace": "Microsoft.UI.Content",
+ "Subtitle": "Create ContentIslands to host other frameworks in your app.",
+ "ImagePath": "ms-appx:///Assets/ControlImages/ContentIsland.png",
+ "Description": "Create ContentIslands to host other frameworks in your app.",
+ "IsNew": true,
+ "Docs": [
+ {
+ "Title": "ContentIsland - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.content.contentisland"
+ }
+ ]
+ },
+ {
+ "UniqueId": "StoragePickers",
+ "Title": "Storage pickers",
+ "ApiNamespace": "Microsoft.Windows.Storage.Pickers",
+ "BaseClasses": [
+ "Object"
+ ],
+ "Subtitle": "Select files and folders with modern system pickers.",
+ "ImagePath": "ms-appx:///Assets/ControlImages/StoragePickers.png",
+ "Description": "Use the FileOpenPicker, FileSavePicker, and FolderPicker APIs to let users select files and folders in a secure way.",
+ "IsUpdated": true,
+ "Docs": [
+ {
+ "Title": "FileOpenPicker - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"
+ },
+ {
+ "Title": "FileSavePicker - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"
+ },
+ {
+ "Title": "FolderPicker - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "UniqueId": "Shell",
+ "Title": "Shell",
+ "IconGlyph": "",
"Items": [
{
"UniqueId": "AppNotification",
@@ -3170,57 +3232,24 @@
]
},
{
- "UniqueId": "Clipboard",
- "Title": "Clipboard",
- "ApiNamespace": "Windows.ApplicationModel.DataTransfer",
- "Subtitle": "Copy and paste to and from the system Clipboard.",
- "ImagePath": "ms-appx:///Assets/ControlImages/Clipboard.png",
- "Description": "Copy and paste to and from the system Clipboard.",
- "Docs": [
- {
- "Title": "Clipboard - API",
- "Uri": "https://learn.microsoft.com/uwp/api/windows.applicationmodel.datatransfer.clipboard"
- }
- ]
- },
- {
- "UniqueId": "ContentIsland",
- "Title": "ContentIsland",
- "ApiNamespace": "Microsoft.UI.Content",
- "Subtitle": "Create ContentIslands to host other frameworks in your app.",
- "ImagePath": "ms-appx:///Assets/ControlImages/ContentIsland.png",
- "Description": "Create ContentIslands to host other frameworks in your app.",
- "IsNew": true,
- "Docs": [
- {
- "Title": "ContentIsland - API",
- "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.content.contentisland"
- }
- ]
- },
- {
- "UniqueId": "StoragePickers",
- "Title": "Storage pickers",
- "ApiNamespace": "Microsoft.Windows.Storage.Pickers",
+ "UniqueId": "JumpList",
+ "Title": "JumpList",
+ "ApiNamespace": "Windows.UI.StartScreen",
"BaseClasses": [
"Object"
],
- "Subtitle": "Select files and folders with modern system pickers.",
- "ImagePath": "ms-appx:///Assets/ControlImages/StoragePickers.png",
- "Description": "Use the FileOpenPicker, FileSavePicker, and FolderPicker APIs to let users select files and folders in a secure way.",
- "IsUpdated": true,
+ "Subtitle": "Add custom tasks and groups to the app's taskbar jump list.",
+ "ImagePath": "ms-appx:///Assets/ControlImages/JumpList.png",
+ "Description": "Jump lists let you add custom tasks and groups to the app's right-click menu on the taskbar. Use them to provide quick access to frequently used actions or recently opened items.",
+ "IsNew": true,
"Docs": [
{
- "Title": "FileOpenPicker - API",
- "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.fileopenpicker"
+ "Title": "JumpList - API",
+ "Uri": "https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplist"
},
{
- "Title": "FileSavePicker - API",
- "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.filesavepicker"
- },
- {
- "Title": "FolderPicker - API",
- "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.pickers.folderpicker"
+ "Title": "JumpListItem - API",
+ "Uri": "https://learn.microsoft.com/uwp/api/windows.ui.startscreen.jumplistitem"
}
]
}
diff --git a/WinUIGallery/WinUIGallery.csproj b/WinUIGallery/WinUIGallery.csproj
index 3c5521e89..f4ea1d4ae 100644
--- a/WinUIGallery/WinUIGallery.csproj
+++ b/WinUIGallery/WinUIGallery.csproj
@@ -176,6 +176,7 @@
+
@@ -367,6 +368,7 @@
+
diff --git a/tests/WinUIGallery.UnitTests/UnitTests.cs b/tests/WinUIGallery.UnitTests/UnitTests.cs
index 2e20e6ab3..948be94ba 100644
--- a/tests/WinUIGallery.UnitTests/UnitTests.cs
+++ b/tests/WinUIGallery.UnitTests/UnitTests.cs
@@ -48,7 +48,8 @@ public async Task TestControlInfoDataSource()
"Text",
"Motion",
"Windowing",
- "System"
+ "System",
+ "Shell"
};
Assert.AreEqual(expectedGroups.Count, groupsList.Count);