Skip to content

Commit 76fb464

Browse files
authored
CmdPal: Bind FilterDropDown selection to the current filter and ensure notifications are raised on UI thread (#41808)
## Summary of the Pull Request This PR declaratively binds FilterDropDown.SelectedValue to CurrentFilterId (one-way only; updates in the opposite direction are handled within the drop-down’s code). It also removes observable properties and reverts to the UpdateProperty style to ensure property change notifications are raised on the UI thread, aligning the handling style with other classes. ## Impact - Fixed a crash that could occur on pages with filters - The filter drop-down now correctly syncs with the initially selected filter when loading a page <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #41578 - [x] Closes: #41649 - [ ] **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 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
1 parent 818db17 commit 76fb464

File tree

3 files changed

+62
-26
lines changed

3 files changed

+62
-26
lines changed

src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/ExtensionObjectViewModel.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,36 @@ protected void UpdateProperty(string propertyName)
5151
DoOnUiThread(() => OnPropertyChanged(propertyName));
5252
}
5353

54+
protected void UpdateProperty(string propertyName1, string propertyName2)
55+
{
56+
DoOnUiThread(() =>
57+
{
58+
OnPropertyChanged(propertyName1);
59+
OnPropertyChanged(propertyName2);
60+
});
61+
}
62+
63+
protected void UpdateProperty(string propertyName1, string propertyName2, string propertyName3)
64+
{
65+
DoOnUiThread(() =>
66+
{
67+
OnPropertyChanged(propertyName1);
68+
OnPropertyChanged(propertyName2);
69+
OnPropertyChanged(propertyName3);
70+
});
71+
}
72+
73+
protected void UpdateProperty(params string[] propertyNames)
74+
{
75+
DoOnUiThread(() =>
76+
{
77+
foreach (var propertyName in propertyNames)
78+
{
79+
OnPropertyChanged(propertyName);
80+
}
81+
});
82+
}
83+
5484
protected void ShowException(Exception ex, string? extensionHint = null)
5585
{
5686
if (PageContext.TryGetTarget(out var pageContext))

src/modules/cmdpal/Microsoft.CmdPal.Core.ViewModels/FiltersViewModel.cs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,18 @@
22
// The Microsoft Corporation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using CommunityToolkit.Mvvm.ComponentModel;
65
using Microsoft.CmdPal.Core.ViewModels.Models;
76
using Microsoft.CommandPalette.Extensions;
87

98
namespace Microsoft.CmdPal.Core.ViewModels;
109

1110
public partial class FiltersViewModel : ExtensionObjectViewModel
1211
{
13-
private readonly ExtensionObject<IFilters> _filtersModel = new(null);
12+
private readonly ExtensionObject<IFilters> _filtersModel;
1413

15-
[ObservableProperty]
16-
public partial string CurrentFilterId { get; set; } = string.Empty;
14+
public string CurrentFilterId { get; private set; } = string.Empty;
1715

18-
[ObservableProperty]
19-
[NotifyPropertyChangedFor(nameof(ShouldShowFilters))]
20-
public partial IFilterItemViewModel[] Filters { get; set; } = [];
16+
public IFilterItemViewModel[] Filters { get; private set; } = [];
2117

2218
public bool ShouldShowFilters => Filters.Length > 0;
2319

@@ -34,23 +30,11 @@ public override void InitializeProperties()
3430
if (_filtersModel.Unsafe is not null)
3531
{
3632
var filters = _filtersModel.Unsafe.GetFilters();
37-
Filters = filters.Select<IFilterItem, IFilterItemViewModel>(filter =>
38-
{
39-
var filterItem = filter as IFilter;
40-
if (filterItem != null)
41-
{
42-
var filterVM = new FilterItemViewModel(filterItem!, PageContext);
43-
filterVM.InitializeProperties();
44-
45-
return filterVM;
46-
}
47-
else
48-
{
49-
return new SeparatorViewModel();
50-
}
51-
}).ToArray();
52-
53-
CurrentFilterId = _filtersModel.Unsafe.CurrentFilterId;
33+
Filters = BuildFilters(filters ?? []);
34+
UpdateProperty(nameof(Filters), nameof(ShouldShowFilters));
35+
36+
CurrentFilterId = _filtersModel.Unsafe.CurrentFilterId ?? string.Empty;
37+
UpdateProperty(nameof(CurrentFilterId));
5438

5539
return;
5640
}
@@ -61,7 +45,27 @@ public override void InitializeProperties()
6145
}
6246

6347
Filters = [];
48+
UpdateProperty(nameof(Filters), nameof(ShouldShowFilters));
49+
6450
CurrentFilterId = string.Empty;
51+
UpdateProperty(nameof(CurrentFilterId));
52+
}
53+
54+
private IFilterItemViewModel[] BuildFilters(IFilterItem[] filters)
55+
{
56+
return [..filters.Select<IFilterItem, IFilterItemViewModel>(filter =>
57+
{
58+
if (filter is IFilter filterItem)
59+
{
60+
var filterItemViewModel = new FilterItemViewModel(filterItem!, PageContext);
61+
filterItemViewModel.InitializeProperties();
62+
return filterItemViewModel;
63+
}
64+
else
65+
{
66+
return new SeparatorViewModel();
67+
}
68+
})];
6569
}
6670

6771
public override void SafeCleanup()
@@ -70,9 +74,9 @@ public override void SafeCleanup()
7074

7175
foreach (var filter in Filters)
7276
{
73-
if (filter is FilterItemViewModel filterVM)
77+
if (filter is FilterItemViewModel filterItemViewModel)
7478
{
75-
filterVM.SafeCleanup();
79+
filterItemViewModel.SafeCleanup();
7680
}
7781
}
7882

src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/FiltersDropDown.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@
7474
ItemsSource="{x:Bind ViewModel.Filters, Mode=OneWay}"
7575
PlaceholderText="Filters"
7676
PreviewKeyDown="FiltersComboBox_PreviewKeyDown"
77+
SelectedValue="{x:Bind ViewModel.CurrentFilterId, Mode=OneWay}"
78+
SelectedValuePath="Id"
7779
SelectionChanged="FiltersComboBox_SelectionChanged"
7880
Style="{StaticResource ComboBoxStyle}"
7981
Visibility="{x:Bind ViewModel.ShouldShowFilters, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">

0 commit comments

Comments
 (0)