mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-20 18:20:27 +01:00
Compare commits
11 Commits
async-cpp-
...
dev/seraph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d28d8e501 | ||
|
|
32492772b8 | ||
|
|
6896f59d48 | ||
|
|
7ce347149f | ||
|
|
626d43f631 | ||
|
|
83aff2687d | ||
|
|
f8837c4ed0 | ||
|
|
9589d3bd74 | ||
|
|
f3b10bfa8e | ||
|
|
3e7c7d77df | ||
|
|
0badb19936 |
@@ -16,21 +16,31 @@ public partial class SamplesListPage : ListPage
|
|||||||
{
|
{
|
||||||
Title = "List Page Sample Command",
|
Title = "List Page Sample Command",
|
||||||
Subtitle = "Display a list of items",
|
Subtitle = "Display a list of items",
|
||||||
|
Section = "Lists",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleListPageWithDetails())
|
new ListItem(new SampleListPageWithDetails())
|
||||||
{
|
{
|
||||||
Title = "List Page With Details",
|
Title = "List Page With Details",
|
||||||
Subtitle = "A list of items, each with additional details to display",
|
Subtitle = "A list of items, each with additional details to display",
|
||||||
|
Section = "Lists",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleUpdatingItemsPage())
|
new ListItem(new SampleUpdatingItemsPage())
|
||||||
{
|
{
|
||||||
Title = "List page with items that change",
|
Title = "List page with items that change",
|
||||||
Subtitle = "The items on the list update themselves in real time",
|
Subtitle = "The items on the list update themselves in real time",
|
||||||
|
Section = "Lists",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleDynamicListPage())
|
new ListItem(new SampleDynamicListPage())
|
||||||
{
|
{
|
||||||
Title = "Dynamic List Page Command",
|
Title = "Dynamic List Page Command",
|
||||||
Subtitle = "Changes the list of items in response to the typed query",
|
Subtitle = "Changes the list of items in response to the typed query",
|
||||||
|
Section = "Lists",
|
||||||
|
},
|
||||||
|
new ListItem(new FizzBuzzListPage())
|
||||||
|
{
|
||||||
|
Title = "Sections sample",
|
||||||
|
Subtitle = "Changing list of items, with sections",
|
||||||
|
Section = "Lists",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Content pages
|
// Content pages
|
||||||
@@ -38,32 +48,38 @@ public partial class SamplesListPage : ListPage
|
|||||||
{
|
{
|
||||||
Title = "Sample content page",
|
Title = "Sample content page",
|
||||||
Subtitle = "Display mixed forms, markdown, and other types of content",
|
Subtitle = "Display mixed forms, markdown, and other types of content",
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleTreeContentPage())
|
new ListItem(new SampleTreeContentPage())
|
||||||
{
|
{
|
||||||
Title = "Sample nested content",
|
Title = "Sample nested content",
|
||||||
Subtitle = "Example of nesting a tree of content",
|
Subtitle = "Example of nesting a tree of content",
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleCommentsPage())
|
new ListItem(new SampleCommentsPage())
|
||||||
{
|
{
|
||||||
Title = "Sample of nested comments",
|
Title = "Sample of nested comments",
|
||||||
Subtitle = "Demo of using nested trees of content to create a comment thread-like experience",
|
Subtitle = "Demo of using nested trees of content to create a comment thread-like experience",
|
||||||
Icon = new IconInfo("\uE90A"), // Comment
|
Icon = new IconInfo("\uE90A"), // Comment
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleMarkdownPage())
|
new ListItem(new SampleMarkdownPage())
|
||||||
{
|
{
|
||||||
Title = "Markdown Page Sample Command",
|
Title = "Markdown Page Sample Command",
|
||||||
Subtitle = "Display a page of rendered markdown",
|
Subtitle = "Display a page of rendered markdown",
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleMarkdownManyBodies())
|
new ListItem(new SampleMarkdownManyBodies())
|
||||||
{
|
{
|
||||||
Title = "Markdown with multiple blocks",
|
Title = "Markdown with multiple blocks",
|
||||||
Subtitle = "A page with multiple blocks of rendered markdown",
|
Subtitle = "A page with multiple blocks of rendered markdown",
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleMarkdownDetails())
|
new ListItem(new SampleMarkdownDetails())
|
||||||
{
|
{
|
||||||
Title = "Markdown with details",
|
Title = "Markdown with details",
|
||||||
Subtitle = "A page with markdown and details",
|
Subtitle = "A page with markdown and details",
|
||||||
|
Section = "Content",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Settings helpers
|
// Settings helpers
|
||||||
@@ -71,6 +87,7 @@ public partial class SamplesListPage : ListPage
|
|||||||
{
|
{
|
||||||
Title = "Sample settings page",
|
Title = "Sample settings page",
|
||||||
Subtitle = "A demo of the settings helpers",
|
Subtitle = "A demo of the settings helpers",
|
||||||
|
Section = "Settings",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Evil edge cases
|
// Evil edge cases
|
||||||
@@ -79,6 +96,7 @@ public partial class SamplesListPage : ListPage
|
|||||||
{
|
{
|
||||||
Title = "Evil samples",
|
Title = "Evil samples",
|
||||||
Subtitle = "Samples designed to break the palette in many different evil ways",
|
Subtitle = "Samples designed to break the palette in many different evil ways",
|
||||||
|
Section = "Debugging",
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||||
|
|
||||||
|
public partial class ListGroup : ObservableObject
|
||||||
|
{
|
||||||
|
public string Key { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial ObservableCollection<ListItemViewModel> Items { get; set; } = [];
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Microsoft Corporation
|
// Copyright (c) Microsoft Corporation
|
||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
@@ -27,6 +27,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
|
|
||||||
private ObservableCollection<ListItemViewModel> Items { get; set; } = [];
|
private ObservableCollection<ListItemViewModel> Items { get; set; } = [];
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial bool HasGrouping { get; private set; } = false;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial ObservableCollection<ListGroup> Groups { get; set; } = [];
|
||||||
|
|
||||||
private readonly ExtensionObject<IListPage> _model;
|
private readonly ExtensionObject<IListPage> _model;
|
||||||
|
|
||||||
private readonly Lock _listLock = new();
|
private readonly Lock _listLock = new();
|
||||||
@@ -248,6 +254,53 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateGroupsIfNeeded()
|
||||||
|
{
|
||||||
|
HasGrouping = FilteredItems.Any(i => !string.IsNullOrEmpty(i.Section));
|
||||||
|
|
||||||
|
if (HasGrouping)
|
||||||
|
{
|
||||||
|
lock (_listLock)
|
||||||
|
{
|
||||||
|
if (FilteredItems.Count == 0)
|
||||||
|
{
|
||||||
|
Groups.Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get current groups
|
||||||
|
var groups = FilteredItems.GroupBy(item => item.Section).Select(group => group);
|
||||||
|
|
||||||
|
// Remove any groups that no longer exist
|
||||||
|
foreach (var group in Groups)
|
||||||
|
{
|
||||||
|
if (!groups.Any(g => g.Key == group.Key))
|
||||||
|
{
|
||||||
|
Groups.Remove(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update lists for each existing group
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
var existingGroup = Groups.FirstOrDefault(groupItem => groupItem.Key == group.Key);
|
||||||
|
if (existingGroup == null)
|
||||||
|
{
|
||||||
|
// Add a new group if it doesn't exist
|
||||||
|
Groups.Add(new ListGroup { Key = group.Key, Items = new ObservableCollection<ListItemViewModel>(group) });
|
||||||
|
existingGroup = Groups.FirstOrDefault(groupItem => groupItem.Key == group.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingGroup != null)
|
||||||
|
{
|
||||||
|
// Update the existing group
|
||||||
|
ListHelpers.InPlaceUpdateList(existingGroup.Items, FilteredItems.Where(item => item.Section == group.Key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply our current filter text to the list of items, and update
|
/// Apply our current filter text to the list of items, and update
|
||||||
/// FilteredItems to match the results.
|
/// FilteredItems to match the results.
|
||||||
@@ -487,6 +540,18 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
FilteredItems.Clear();
|
FilteredItems.Clear();
|
||||||
|
|
||||||
|
foreach (ListGroup group in Groups)
|
||||||
|
{
|
||||||
|
foreach (ListItemViewModel item in group.Items)
|
||||||
|
{
|
||||||
|
item.SafeCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
group.Items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Groups.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
IListPage? model = _model.Unsafe;
|
IListPage? model = _model.Unsafe;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<!-- Other merged dictionaries here -->
|
<!-- Other merged dictionaries here -->
|
||||||
<ResourceDictionary Source="Styles/Button.xaml" />
|
<ResourceDictionary Source="Styles/Button.xaml" />
|
||||||
<ResourceDictionary Source="Styles/Colors.xaml" />
|
<ResourceDictionary Source="Styles/Colors.xaml" />
|
||||||
|
<ResourceDictionary Source="Styles/Generic.xaml" />
|
||||||
<ResourceDictionary Source="Styles/TextBox.xaml" />
|
<ResourceDictionary Source="Styles/TextBox.xaml" />
|
||||||
<ResourceDictionary Source="Styles/Settings.xaml" />
|
<ResourceDictionary Source="Styles/Settings.xaml" />
|
||||||
<ResourceDictionary Source="Controls/Tag.xaml" />
|
<ResourceDictionary Source="Controls/Tag.xaml" />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<Page
|
<Page
|
||||||
x:Class="Microsoft.CmdPal.UI.ListPage"
|
x:Class="Microsoft.CmdPal.UI.ListPage"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
@@ -17,10 +17,16 @@
|
|||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<!-- TODO: Figure out what we want to do here for filtering/grouping and where -->
|
<!-- TODO: Figure out what we want to do here for filtering/grouping and where -->
|
||||||
<!-- https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.collectionviewsource -->
|
<!-- https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.collectionviewsource -->
|
||||||
<!--<CollectionViewSource
|
<CollectionViewSource
|
||||||
x:Name="ItemsCVS"
|
x:Name="GroupedItemsCVS"
|
||||||
IsSourceGrouped="True"
|
IsSourceGrouped="True"
|
||||||
Source="{x:Bind ViewModel.Items, Mode=OneWay}" />-->
|
ItemsPath="Items"
|
||||||
|
Source="{x:Bind ViewModel.Groups, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<CollectionViewSource
|
||||||
|
x:Name="UngroupedItemsCVS"
|
||||||
|
IsSourceGrouped="False"
|
||||||
|
Source="{x:Bind ViewModel.FilteredItems, Mode=OneWay}" />
|
||||||
|
|
||||||
<converters:StringVisibilityConverter
|
<converters:StringVisibilityConverter
|
||||||
x:Key="StringVisibilityConverter"
|
x:Key="StringVisibilityConverter"
|
||||||
@@ -107,32 +113,74 @@
|
|||||||
TargetType="x:Boolean"
|
TargetType="x:Boolean"
|
||||||
Value="{x:Bind ViewModel.ShowEmptyContent, Mode=OneWay}">
|
Value="{x:Bind ViewModel.ShowEmptyContent, Mode=OneWay}">
|
||||||
<controls:Case Value="False">
|
<controls:Case Value="False">
|
||||||
<ListView
|
<controls:SwitchPresenter
|
||||||
x:Name="ItemsList"
|
HorizontalAlignment="Stretch"
|
||||||
Padding="0,2,0,0"
|
TargetType="x:Boolean"
|
||||||
DoubleTapped="ItemsList_DoubleTapped"
|
Value="{x:Bind ViewModel.HasGrouping, Mode=OneWay}">
|
||||||
IsDoubleTapEnabled="True"
|
<controls:Case Value="True">
|
||||||
IsItemClickEnabled="True"
|
<ListView
|
||||||
ItemClick="ItemsList_ItemClick"
|
x:Name="GroupedItemsList"
|
||||||
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
Padding="0,2,0,0"
|
||||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
DoubleTapped="GroupedItemsList_DoubleTapped"
|
||||||
SelectionChanged="ItemsList_SelectionChanged">
|
IsDoubleTapEnabled="True"
|
||||||
<ListView.ItemContainerTransitions>
|
IsItemClickEnabled="True"
|
||||||
<TransitionCollection />
|
ItemClick="ItemsList_ItemClick"
|
||||||
</ListView.ItemContainerTransitions>
|
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
||||||
<!--<ListView.GroupStyle>
|
ItemsSource="{Binding ElementName=GroupedItemsCVS, Path=View}"
|
||||||
<GroupStyle HidesIfEmpty="True">
|
SelectionChanged="GroupedItemsList_SelectionChanged">
|
||||||
<GroupStyle.HeaderTemplate>
|
<ListView.ItemContainerTransitions>
|
||||||
<DataTemplate>
|
<TransitionCollection />
|
||||||
<TextBlock
|
</ListView.ItemContainerTransitions>
|
||||||
Margin="0,16,0,0"
|
<ListView.GroupStyle>
|
||||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
<!--<GroupStyle HeaderContainerStyle="{StaticResource CustomHeaderContainerStyle}" HidesIfEmpty="True">
|
||||||
Text="{Binding Key, Mode=OneWay}" />
|
<GroupStyle.HeaderTemplate>
|
||||||
</DataTemplate>
|
<DataTemplate>
|
||||||
</GroupStyle.HeaderTemplate>
|
<TextBlock
|
||||||
</GroupStyle>
|
Padding="20,12,0,8"
|
||||||
</ListView.GroupStyle>-->
|
AutomationProperties.AccessibilityView="Raw"
|
||||||
</ListView>
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Text="{x:Bind Key}"
|
||||||
|
Visibility="{x:Bind Key, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GroupStyle.HeaderTemplate>
|
||||||
|
</GroupStyle>-->
|
||||||
|
|
||||||
|
<GroupStyle HeaderContainerStyle="{StaticResource CustomHeaderContainerStyle}" HidesIfEmpty="True">
|
||||||
|
<GroupStyle.HeaderTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,16,0,0"
|
||||||
|
Padding="20,8,0,4"
|
||||||
|
AutomationProperties.AccessibilityView="Raw"
|
||||||
|
FontSize="14"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||||
|
Text="{Binding Key, Mode=OneWay}"
|
||||||
|
Visibility="{Binding Key, Converter={StaticResource StringVisibilityConverter}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GroupStyle.HeaderTemplate>
|
||||||
|
</GroupStyle>
|
||||||
|
</ListView.GroupStyle>
|
||||||
|
</ListView>
|
||||||
|
</controls:Case>
|
||||||
|
<controls:Case Value="False">
|
||||||
|
<ListView
|
||||||
|
x:Name="ItemsList"
|
||||||
|
Padding="0,2,0,0"
|
||||||
|
DoubleTapped="ItemsList_DoubleTapped"
|
||||||
|
IsDoubleTapEnabled="True"
|
||||||
|
IsItemClickEnabled="True"
|
||||||
|
ItemClick="ItemsList_ItemClick"
|
||||||
|
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
||||||
|
ItemsSource="{Binding ElementName=UngroupedItemsCVS, Path=View}"
|
||||||
|
SelectionChanged="ItemsList_SelectionChanged">
|
||||||
|
<ListView.ItemContainerTransitions>
|
||||||
|
<TransitionCollection />
|
||||||
|
</ListView.ItemContainerTransitions>
|
||||||
|
</ListView>
|
||||||
|
</controls:Case>
|
||||||
|
</controls:SwitchPresenter>
|
||||||
</controls:Case>
|
</controls:Case>
|
||||||
<controls:Case Value="True">
|
<controls:Case Value="True">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public sealed partial class ListPage : Page,
|
|||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
this.NavigationCacheMode = NavigationCacheMode.Disabled;
|
this.NavigationCacheMode = NavigationCacheMode.Disabled;
|
||||||
this.ItemsList.Loaded += ItemsList_Loaded;
|
this.ItemsList.Loaded += ItemsList_Loaded;
|
||||||
|
this.GroupedItemsList.Loaded += GroupedItemsList_Loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
@@ -121,6 +122,18 @@ public sealed partial class ListPage : Page,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GroupedItemsList_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (GroupedItemsList.SelectedItem is ListItemViewModel vm)
|
||||||
|
{
|
||||||
|
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||||
|
if (!settings.SingleClickActivates)
|
||||||
|
{
|
||||||
|
ViewModel?.InvokeItemCommand.Execute(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
||||||
private void ItemsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void ItemsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -148,6 +161,24 @@ public sealed partial class ListPage : Page,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS is too aggressive at pruning methods bound in XAML")]
|
||||||
|
private void GroupedItemsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (GroupedItemsList.SelectedItem is ListItemViewModel item)
|
||||||
|
{
|
||||||
|
var vm = ViewModel;
|
||||||
|
_ = Task.Run(() =>
|
||||||
|
{
|
||||||
|
vm?.UpdateSelectedItemCommand.Execute(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GroupedItemsList.SelectedItem != null)
|
||||||
|
{
|
||||||
|
GroupedItemsList.ScrollIntoView(GroupedItemsList.SelectedItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ItemsList_Loaded(object sender, RoutedEventArgs e)
|
private void ItemsList_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
// Find the ScrollViewer in the ListView
|
// Find the ScrollViewer in the ListView
|
||||||
@@ -159,6 +190,17 @@ public sealed partial class ListPage : Page,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GroupedItemsList_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Find the ScrollViewer in the ListView
|
||||||
|
var listViewScrollViewer = FindScrollViewer(this.GroupedItemsList);
|
||||||
|
|
||||||
|
if (listViewScrollViewer != null)
|
||||||
|
{
|
||||||
|
listViewScrollViewer.ViewChanged += ListViewScrollViewer_ViewChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ListViewScrollViewer_ViewChanged(object? sender, ScrollViewerViewChangedEventArgs e)
|
private void ListViewScrollViewer_ViewChanged(object? sender, ScrollViewerViewChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var scrollView = sender as ScrollViewer;
|
var scrollView = sender as ScrollViewer;
|
||||||
@@ -187,6 +229,11 @@ public sealed partial class ListPage : Page,
|
|||||||
{
|
{
|
||||||
ItemsList.SelectedIndex++;
|
ItemsList.SelectedIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GroupedItemsList.SelectedIndex < GroupedItemsList.Items.Count - 1)
|
||||||
|
{
|
||||||
|
GroupedItemsList.SelectedIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(NavigatePreviousCommand message)
|
public void Receive(NavigatePreviousCommand message)
|
||||||
@@ -195,6 +242,11 @@ public sealed partial class ListPage : Page,
|
|||||||
{
|
{
|
||||||
ItemsList.SelectedIndex--;
|
ItemsList.SelectedIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GroupedItemsList.SelectedIndex > 0)
|
||||||
|
{
|
||||||
|
GroupedItemsList.SelectedIndex--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(ActivateSelectedListItemMessage message)
|
public void Receive(ActivateSelectedListItemMessage message)
|
||||||
@@ -207,6 +259,10 @@ public sealed partial class ListPage : Page,
|
|||||||
{
|
{
|
||||||
ViewModel?.InvokeItemCommand.Execute(item);
|
ViewModel?.InvokeItemCommand.Execute(item);
|
||||||
}
|
}
|
||||||
|
else if (GroupedItemsList.SelectedItem is ListItemViewModel groupedItem)
|
||||||
|
{
|
||||||
|
ViewModel?.InvokeItemCommand.Execute(groupedItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(ActivateSecondaryCommandMessage message)
|
public void Receive(ActivateSecondaryCommandMessage message)
|
||||||
@@ -219,6 +275,10 @@ public sealed partial class ListPage : Page,
|
|||||||
{
|
{
|
||||||
ViewModel?.InvokeSecondaryCommandCommand.Execute(item);
|
ViewModel?.InvokeSecondaryCommandCommand.Execute(item);
|
||||||
}
|
}
|
||||||
|
else if (GroupedItemsList.SelectedItem is ListItemViewModel groupedItem)
|
||||||
|
{
|
||||||
|
ViewModel?.InvokeSecondaryCommandCommand.Execute(groupedItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
private static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
@@ -247,6 +307,11 @@ public sealed partial class ListPage : Page,
|
|||||||
// GetItems or a change in the filter.
|
// GetItems or a change in the filter.
|
||||||
private void Page_ItemsUpdated(ListViewModel sender, object args)
|
private void Page_ItemsUpdated(ListViewModel sender, object args)
|
||||||
{
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel?.UpdateGroupsIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
// If for some reason, we don't have a selected item, fix that.
|
// If for some reason, we don't have a selected item, fix that.
|
||||||
//
|
//
|
||||||
// It's important to do this here, because once there's no selection
|
// It's important to do this here, because once there's no selection
|
||||||
@@ -258,6 +323,11 @@ public sealed partial class ListPage : Page,
|
|||||||
{
|
{
|
||||||
ItemsList.SelectedIndex = 0;
|
ItemsList.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GroupedItemsList.SelectedItem == null)
|
||||||
|
{
|
||||||
|
GroupedItemsList.SelectedIndex = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
|||||||
29
src/modules/cmdpal/Microsoft.CmdPal.UI/Styles/Generic.xaml
Normal file
29
src/modules/cmdpal/Microsoft.CmdPal.UI/Styles/Generic.xaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<!-- Using custom style to remove header divider from list view headers -->
|
||||||
|
<Style x:Key="CustomHeaderContainerStyle" TargetType="ListViewHeaderItem">
|
||||||
|
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||||
|
<Setter Property="FontSize" Value="{ThemeResource ListViewHeaderItemThemeFontSize}" />
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="Padding" Value="12,8,12,0" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||||
|
<Setter Property="MinHeight" Value="0" />
|
||||||
|
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ListViewHeaderItem">
|
||||||
|
<ContentPresenter
|
||||||
|
x:Name="ContentPresenter"
|
||||||
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
Content="{TemplateBinding Content}"
|
||||||
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
|
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.CommandPalette.Extensions;
|
||||||
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
|
||||||
|
namespace SamplePagesExtension;
|
||||||
|
|
||||||
|
internal sealed partial class FizzBuzzListPage : ListPage
|
||||||
|
{
|
||||||
|
public override string Title => "FizzBuzz Page";
|
||||||
|
|
||||||
|
public override IconInfo Icon => new("\uE94C"); // % symbol
|
||||||
|
|
||||||
|
public override string Name => "Open";
|
||||||
|
|
||||||
|
private readonly List<ListItem> _items;
|
||||||
|
|
||||||
|
internal FizzBuzzListPage()
|
||||||
|
{
|
||||||
|
var addNewItem = new ListItem(new AnonymousCommand(() =>
|
||||||
|
{
|
||||||
|
var c = _items.Count;
|
||||||
|
var f = c % 3 == 0;
|
||||||
|
var b = c % 5 == 0;
|
||||||
|
var s = string.Empty;
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
s += "Fizz";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b)
|
||||||
|
{
|
||||||
|
s += "Buzz";
|
||||||
|
}
|
||||||
|
|
||||||
|
_items.Add(new ListItem(new NoOpCommand())
|
||||||
|
{
|
||||||
|
Title = $"{c}",
|
||||||
|
Icon = IconFromIndex(_items.Count),
|
||||||
|
Section = s,
|
||||||
|
});
|
||||||
|
RaiseItemsChanged();
|
||||||
|
})
|
||||||
|
{ Result = CommandResult.KeepOpen() })
|
||||||
|
{
|
||||||
|
Title = "Add item",
|
||||||
|
Subtitle = "Each item will be sorted into sections. Add at least three",
|
||||||
|
Icon = new IconInfo("\uED0E"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_items = [addNewItem];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IListItem[] GetItems()
|
||||||
|
{
|
||||||
|
return _items.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IconInfo IconFromIndex(int index)
|
||||||
|
{
|
||||||
|
return _icons[index % _icons.Length];
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IconInfo[] _icons =
|
||||||
|
[
|
||||||
|
new IconInfo("\ue700"),
|
||||||
|
new IconInfo("\ue701"),
|
||||||
|
new IconInfo("\ue702"),
|
||||||
|
new IconInfo("\ue703"),
|
||||||
|
new IconInfo("\ue704"),
|
||||||
|
new IconInfo("\ue705"),
|
||||||
|
new IconInfo("\ue706"),
|
||||||
|
new IconInfo("\ue707"),
|
||||||
|
new IconInfo("\ue708"),
|
||||||
|
new IconInfo("\ue709"),
|
||||||
|
new IconInfo("\ue70a"),
|
||||||
|
new IconInfo("\ue70b"),
|
||||||
|
new IconInfo("\ue70c"),
|
||||||
|
new IconInfo("\ue70d"),
|
||||||
|
new IconInfo("\ue70e"),
|
||||||
|
new IconInfo("\ue70f"),
|
||||||
|
new IconInfo("\ue710"),
|
||||||
|
new IconInfo("\ue711"),
|
||||||
|
new IconInfo("\ue712"),
|
||||||
|
new IconInfo("\ue713"),
|
||||||
|
];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user