mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
[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:  ### After:  <!-- 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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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.",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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") },
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user