[CmdPal] Fix filters visibility on non-ListPage (#42828)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This PR aims to fix the issue where filters from a ListPage remain
visible when navigating to other pages.
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #42827 
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
### Before:

![FiltersIssue](https://github.com/user-attachments/assets/b0ad6059-9a11-4e12-821d-7202358e25bb)

### After:

![FiltersFix](https://github.com/user-attachments/assets/b9ee71ee-cb5d-4ef9-b9fc-bc2e2a710b5c)

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Jiří Polášek <me@jiripolasek.com>
This commit is contained in:
Guilherme
2025-10-28 16:32:09 -03:00
committed by GitHub
parent c4e96c7ee9
commit de00cbf20a
6 changed files with 133 additions and 3 deletions

View File

@@ -97,6 +97,17 @@ public partial class ListViewModel : PageViewModel, IDisposable
EmptyContent = new(new(null), PageContext);
}
private void FiltersPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(FiltersViewModel.Filters))
{
var filtersViewModel = sender as FiltersViewModel;
var hasFilters = filtersViewModel?.Filters.Length > 0;
HasFilters = hasFilters;
UpdateProperty(nameof(HasFilters));
}
}
// TODO: Does this need to hop to a _different_ thread, so that we don't block the extension while we're fetching?
private void Model_ItemsChanged(object sender, IItemsChangedEventArgs args) => FetchItems();
@@ -586,8 +597,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent.SlowInitializeProperties();
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters.InitializeProperties();
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
UpdateProperty(nameof(Filters));
FetchItems();
@@ -686,8 +700,10 @@ public partial class ListViewModel : PageViewModel, IDisposable
EmptyContent.SlowInitializeProperties();
break;
case nameof(Filters):
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters.InitializeProperties();
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
break;
case nameof(IsLoading):
UpdateEmptyContent();
@@ -757,6 +773,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
FilteredItems.Clear();
}
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters?.SafeCleanup();
var model = _model.Unsafe;

View File

@@ -70,6 +70,8 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
public bool HasSearchBox { get; protected set; } = true;
public bool HasFilters { get; protected set; }
public IconInfoViewModel Icon { get; protected set; }
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost)

View File

@@ -77,7 +77,7 @@
SelectedValue="{x:Bind ViewModel.CurrentFilter, Mode=OneWay}"
SelectionChanged="FiltersComboBox_SelectionChanged"
Style="{StaticResource ComboBoxStyle}"
Visibility="{x:Bind ViewModel.ShouldShowFilters, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
Visibility="{x:Bind ViewModel.ShouldShowFilters, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Collapsed}">
<ComboBox.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultComboBoxItemStyle}" TargetType="ComboBoxItem">
<Setter Property="MinHeight" Value="0" />

View File

@@ -0,0 +1,29 @@
// 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 Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension.Pages.IssueSpecificPages;
internal sealed partial class AllIssueSamplesIndexPage : ListPage
{
public AllIssueSamplesIndexPage()
{
Icon = new IconInfo("🐛");
Name = "All Issue Samples Index Page";
}
public override IListItem[] GetItems()
{
return new IListItem[]
{
new ListItem(new SamplePageForIssue42827_FilterDropDownStaysVisibleAfterSwitchingFromListToContentPage())
{
Title = "Issue 42827 - Filter Drop Down Stays Visible After Switching From List To Content Page",
Subtitle = "Repro steps: Open this page, open the filter dropdown, select a filter, navigate to a content page, navigate back to this page. The filter dropdown should be closed but it remains open.",
},
};
}
}

View File

@@ -0,0 +1,76 @@
// 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.Linq;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension.Pages.IssueSpecificPages;
internal sealed partial class SamplePageForIssue42827_FilterDropDownStaysVisibleAfterSwitchingFromListToContentPage : DynamicListPage
{
public SamplePageForIssue42827_FilterDropDownStaysVisibleAfterSwitchingFromListToContentPage()
{
Icon = new IconInfo(string.Empty);
Name = "Issue 42827 - Filters not hiding when navigating between pages";
IsLoading = true;
var filters = new SampleFilters();
filters.PropChanged += Filters_PropChanged;
Filters = filters;
}
private void Filters_PropChanged(object sender, IPropChangedEventArgs args) => RaiseItemsChanged();
public override void UpdateSearchText(string oldSearch, string newSearch) => RaiseItemsChanged();
public override IListItem[] GetItems()
{
var items = SearchText.ToCharArray().Select(ch => new ListItem(new SampleContentPage()) { Title = ch.ToString() }).ToArray();
if (items.Length == 0)
{
items = [
new ListItem(new SampleContentPage()) { Title = "This List item will open a content page" },
new ListItem(new SampleContentPage()) { Title = "This List item will open a content page too" },
new ListItem(new SampleContentPage()) { Title = "Guess what this one will do?" },
];
}
if (!string.IsNullOrEmpty(Filters.CurrentFilterId))
{
switch (Filters.CurrentFilterId)
{
case "mod2":
items = items.Where((item, index) => (index + 1) % 2 == 0).ToArray();
break;
case "mod3":
items = items.Where((item, index) => (index + 1) % 3 == 0).ToArray();
break;
case "all":
default:
// No filtering
break;
}
}
foreach (var item in items)
{
item.Subtitle = "Filter drop-down should be hidden when navigating to a content page";
}
return items;
}
internal sealed partial class SampleFilters : Filters
{
public override IFilterItem[] GetFilters()
{
return
[
new Filter() { Id = "all", Name = "All" },
new Filter() { Id = "mod2", Name = "Every 2nd", Icon = new IconInfo("2") },
new Filter() { Id = "mod3", Name = "Every 3rd (and long name)", Icon = new IconInfo("3") },
];
}
}
}

View File

@@ -5,6 +5,7 @@
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using SamplePagesExtension.Pages;
using SamplePagesExtension.Pages.IssueSpecificPages;
namespace SamplePagesExtension;
@@ -106,6 +107,11 @@ public partial class SamplesListPage : ListPage
{
Title = "Evil samples",
Subtitle = "Samples designed to break the palette in many different evil ways",
},
new ListItem(new AllIssueSamplesIndexPage())
{
Title = "Issue-specific samples",
Subtitle = "Samples designed to reproduce specific issues",
}
];