Skip to content

Commit 92754e1

Browse files
authored
Merge pull request #378 from w-ahmad/fix/filter-flyout-popup-issue
Fix filter flyout search behavior by using custom MenuFlyout control
2 parents 3bce6e5 + 29a6bee commit 92754e1

5 files changed

Lines changed: 244 additions & 124 deletions

src/Controls/TableViewFilterItemsControl.xaml.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,7 @@ internal async void Initialize()
4949
/// </summary>
5050
internal void ClearSearchBox()
5151
{
52-
if (searchBox is not null)
53-
{
54-
searchBox.Text = string.Empty;
55-
}
52+
searchBox?.Text = string.Empty;
5653
}
5754

5855
private void OnSearchBoxTextChanged(object sender, TextChangedEventArgs e)
@@ -67,7 +64,8 @@ private void OnSearchBoxKeyDown(object sender, KeyRoutedEventArgs e)
6764
{
6865
if (e.Key == VirtualKey.Enter && searchBox?.Text.Length > 0)
6966
{
70-
ColumnHeader?.ExecuteOkCommand();
67+
ColumnHeader?.HideFlyout();
68+
ColumnHeader?.ApplyFilter();
7169

7270
e.Handled = true;
7371
}
@@ -175,7 +173,19 @@ internal ICollection<TableViewFilterItem>? FilterItems
175173
/// <summary>
176174
/// Gets or sets the column header associated with the filter items control.
177175
/// </summary>
178-
public TableViewColumnHeader? ColumnHeader { get; internal set; }
176+
public TableViewColumnHeader? ColumnHeader
177+
{
178+
get;
179+
set
180+
{
181+
if (value is { FilterItemsControl: null })
182+
{
183+
value.FilterItemsControl = this;
184+
}
185+
186+
field = value;
187+
}
188+
}
179189

180190
/// <summary>
181191
/// Gets or sets the TableView associated with the filter items control.

src/TableViewColumnHeader.OptionComamnds.cs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Microsoft.UI.Xaml.Controls;
22
using Microsoft.UI.Xaml.Input;
3-
using WinUI.TableView.Extensions;
43
using SD = WinUI.TableView.SortDirection;
54

65
namespace WinUI.TableView;
@@ -11,9 +10,7 @@ partial class TableViewColumnHeader
1110
private readonly StandardUICommand _sortAscendingCommand = new() { Label = TableViewLocalizedStrings.SortAscending };
1211
private readonly StandardUICommand _sortDescendingCommand = new() { Label = TableViewLocalizedStrings.SortDescending };
1312
private readonly StandardUICommand _clearSortingCommand = new() { Label = TableViewLocalizedStrings.ClearSorting };
14-
private readonly StandardUICommand _clearFilterCommand = new() { Label = TableViewLocalizedStrings.ClearFilter };
15-
private readonly StandardUICommand _okCommand = new() { Label = TableViewLocalizedStrings.Ok };
16-
private readonly StandardUICommand _cancelCommand = new() { Label = TableViewLocalizedStrings.Cancel };
13+
private readonly StandardUICommand _clearFilterCommand = new() { Label = TableViewLocalizedStrings.ClearFilter };
1714

1815
/// <summary>
1916
/// Sets commands to option menu items.
@@ -30,15 +27,6 @@ private void SetOptionCommands()
3027
clearSortingMenuItem.Command = _clearSortingCommand;
3128
if (GetTemplateChild("ClearFilterMenuItem") is MenuFlyoutItem clearFilterMenuItem)
3229
clearFilterMenuItem.Command = _clearFilterCommand;
33-
if (GetTemplateChild("ActionButtonsMenuItem") is MenuFlyoutItem actionButtonsMenuItem)
34-
{
35-
actionButtonsMenuItem.ApplyTemplate();
36-
37-
if (actionButtonsMenuItem.FindDescendant<Button>(b => b.Name is "OkButton") is { } okButton)
38-
okButton.Command = _okCommand;
39-
if (actionButtonsMenuItem.FindDescendant<Button>(b => b.Name is "CancelButton") is { } cancelButton)
40-
cancelButton.Command = _cancelCommand;
41-
}
4230
}
4331

4432
/// <summary>
@@ -62,16 +50,7 @@ private void InitializeCommands()
6250

6351
_clearFilterCommand.ExecuteRequested += delegate { ClearFilter(); };
6452
_clearFilterCommand.CanExecuteRequested += (_, e) => e.CanExecute = Column?.IsFiltered is true;
65-
66-
_okCommand.ExecuteRequested += delegate { ExecuteOkCommand(); };
67-
68-
_cancelCommand.ExecuteRequested += delegate { HideFlyout(); };
53+
6954
_commandsInitialized = true;
7055
}
71-
72-
internal void ExecuteOkCommand()
73-
{
74-
HideFlyout();
75-
ApplyFilter();
76-
}
7756
}

src/TableViewColumnHeader.cs

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,15 @@ public partial class TableViewColumnHeader : ContentControl
3737
private TableView? _tableView;
3838
private TableViewHeaderRow? _headerRow;
3939
private Button? _optionsButton;
40-
private MenuFlyout? _optionsFlyout;
41-
private MenuFlyoutItem? _filterItemsMenuItem;
40+
private TableViewFilterMenuFlyout? _optionsFlyout;
4241
private ContentPresenter? _contentPresenter;
4342
private Rectangle? _v_gridLine;
4443
private bool _resizeStarted;
4544
private double _resizeStartingWidth;
4645
private bool _resizePreviousStarted;
4746
private double _reorderStartingPosition;
4847
private bool _reorderStarted;
49-
private RenderTargetBitmap? _dragVisuals;
50-
private TableViewFilterItemsControl? _filterItemsControl;
48+
private RenderTargetBitmap? _dragVisuals;
5149

5250
/// <summary>
5351
/// Initializes a new instance of the TableViewColumnHeader class.
@@ -156,9 +154,9 @@ private void ClearFilter()
156154
/// <summary>
157155
/// Applies the filter for the column.
158156
/// </summary>
159-
private void ApplyFilter()
157+
internal void ApplyFilter()
160158
{
161-
var shouldApplyFilter = _filterItemsControl?.ShouldApplyFilter ?? false;
159+
var shouldApplyFilter = FilterItemsControl?.ShouldApplyFilter ?? false;
162160

163161
if (!shouldApplyFilter && (Column?.IsFiltered ?? false))
164162
{
@@ -173,7 +171,7 @@ private void ApplyFilter()
173171

174172
private ICollection<object?> GetSelectedValues()
175173
{
176-
var filterItems = _filterItemsControl?.FilterItems ?? [];
174+
var filterItems = FilterItemsControl?.FilterItems ?? [];
177175
var selectedValues = filterItems.Where(x => x.IsSelected).Select(x => x.Value);
178176
var firstItem = selectedValues.FirstOrDefault(x => x is not null);
179177
var firstItemType = firstItem?.GetType();
@@ -197,7 +195,7 @@ private void ApplyFilter()
197195
/// <summary>
198196
/// Hides the options flyout.
199197
/// </summary>
200-
private void HideFlyout()
198+
internal void HideFlyout()
201199
{
202200
_optionsFlyout?.Hide();
203201
}
@@ -231,20 +229,16 @@ protected override void OnApplyTemplate()
231229
{
232230
base.OnApplyTemplate();
233231

234-
_optionsFlyout?.Opening -= OnOptionsFlyoutOpening;
235-
_optionsFlyout?.Closed -= OnOptionsFlyoutClosed;
236232
_optionsButton?.Tapped -= OnOptionsButtonTaped;
237-
_filterItemsMenuItem?.PreviewKeyUp -= OnFilterItemsMenuItemPreviewKeyUp;
238233

239-
_filterItemsControl?.FilterItems = null;
240-
_filterItemsControl?.TableView = null;
241-
_filterItemsControl?.ColumnHeader = null;
242-
_filterItemsControl = null;
234+
FilterItemsControl?.FilterItems = null;
235+
FilterItemsControl?.TableView = null;
236+
FilterItemsControl?.ColumnHeader = null;
237+
FilterItemsControl = null;
243238
_tableView = this.FindAscendant<TableView>();
244239
_headerRow = this.FindAscendant<TableViewHeaderRow>();
245240
_optionsButton = GetTemplateChild("OptionsButton") as Button;
246-
_optionsFlyout = GetTemplateChild("OptionsFlyout") as MenuFlyout;
247-
_filterItemsMenuItem = GetTemplateChild("FilterItemsMenuItem") as MenuFlyoutItem;
241+
_optionsFlyout = GetTemplateChild("OptionsFlyout") as TableViewFilterMenuFlyout;
248242
_contentPresenter = GetTemplateChild("ContentPresenter") as ContentPresenter;
249243
_v_gridLine = GetTemplateChild("VerticalGridLine") as Rectangle;
250244

@@ -253,39 +247,16 @@ protected override void OnApplyTemplate()
253247
return;
254248
}
255249

256-
_optionsFlyout.Opening += OnOptionsFlyoutOpening;
257-
_optionsFlyout.Closed += OnOptionsFlyoutClosed;
258-
_optionsButton.Tapped += OnOptionsButtonTaped;
259-
260-
_filterItemsMenuItem?.ApplyTemplate();
261-
_filterItemsControl = _filterItemsMenuItem?.FindDescendant<TableViewFilterItemsControl>();
262-
263-
_filterItemsControl?.TableView = _tableView;
264-
_filterItemsControl?.ColumnHeader = this;
250+
_optionsFlyout.TableView = _tableView;
251+
_optionsFlyout.ColumnHeader = this;
265252

266-
_filterItemsMenuItem?.PreviewKeyUp += OnFilterItemsMenuItemPreviewKeyUp;
253+
_optionsButton.Tapped += OnOptionsButtonTaped;
267254

268255
SetOptionCommands();
269256
SetFilterButtonVisibility();
270257
EnsureGridLines();
271258
}
272259

273-
/// <summary>
274-
/// Handles the Opening event for the options flyout.
275-
/// </summary>
276-
private async void OnOptionsFlyoutOpening(object? sender, object e)
277-
{
278-
_filterItemsControl?.Initialize();
279-
}
280-
281-
/// <summary>
282-
/// Handles the Closed event for the options flyout.
283-
/// </summary>
284-
private void OnOptionsFlyoutClosed(object? sender, object e)
285-
{
286-
_filterItemsControl?.ClearSearchBox();
287-
}
288-
289260
/// <summary>
290261
/// Handles the Tapped event for the options button.
291262
/// </summary>
@@ -294,14 +265,6 @@ private void OnOptionsButtonTaped(object sender, TappedRoutedEventArgs e)
294265
e.Handled = true;
295266
}
296267

297-
/// <summary>
298-
/// Handles the PreviewKeyUp event for the filter items menu item.
299-
/// </summary>
300-
private void OnFilterItemsMenuItemPreviewKeyUp(object sender, KeyRoutedEventArgs e)
301-
{
302-
e.Handled = e.Key is VirtualKey.Space;
303-
}
304-
305268
/// <summary>
306269
/// Handles changes to the SortDirection property.
307270
/// </summary>
@@ -565,4 +528,9 @@ internal void EnsureGridLines()
565528
/// Gets a value indicating whether the cursor is in the sizing area.
566529
/// </summary>
567530
private bool IsSizingCursor => ProtectedCursor is InputSystemCursor { CursorShape: InputSystemCursorShape.SizeWestEast };
531+
532+
/// <summary>
533+
/// Gets or sets the filter items control associated with the column header.
534+
/// </summary>
535+
internal TableViewFilterItemsControl? FilterItemsControl { get; set; }
568536
}

src/TableViewFilterMenuFlyout.cs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using Microsoft.UI.Xaml;
2+
using Microsoft.UI.Xaml.Controls;
3+
using Microsoft.UI.Xaml.Input;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using WinUI.TableView.Controls;
7+
using WinUI.TableView.Extensions;
8+
9+
namespace WinUI.TableView;
10+
11+
/// <summary>
12+
/// Represents the filter menu flyout for a TableViewColumnHeader.
13+
/// </summary>
14+
public partial class TableViewFilterMenuFlyout : Flyout
15+
{
16+
private TableViewFilterItemsControl? _filterItemsControl;
17+
private readonly StandardUICommand _okCommand = new() { Label = TableViewLocalizedStrings.Ok };
18+
private readonly StandardUICommand _cancelCommand = new() { Label = TableViewLocalizedStrings.Cancel };
19+
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="TableViewFilterMenuFlyout"/> class.
22+
/// </summary>
23+
public TableViewFilterMenuFlyout()
24+
{
25+
Items = [];
26+
Opening += OnOpening;
27+
Closed += OnClosed;
28+
29+
_okCommand.ExecuteRequested += delegate { ExecuteOkCommand(); };
30+
_cancelCommand.ExecuteRequested += delegate { Hide(); };
31+
}
32+
33+
/// <inheritdoc/>
34+
protected override Control CreatePresenter()
35+
{
36+
var presenter = base.CreatePresenter();
37+
presenter.Style = FlyoutPresenterStyle;
38+
presenter.Loaded += OnPresenterLoaded;
39+
40+
return presenter;
41+
}
42+
43+
/// <summary>
44+
/// Handles the Opening event of the flyout, initializing the filter items control.
45+
/// </summary>
46+
private void OnOpening(object? sender, object e)
47+
{
48+
_filterItemsControl?.Initialize();
49+
}
50+
51+
/// <summary>
52+
/// Handles the Closed event of the flyout, clearing the search box in the filter items control.
53+
/// </summary>
54+
private void OnClosed(object? sender, object e)
55+
{
56+
_filterItemsControl?.ClearSearchBox();
57+
}
58+
59+
/// <summary>
60+
/// Handles the Loaded event of the MenuFlyoutPresenter.
61+
/// </summary>
62+
private void OnPresenterLoaded(object sender, RoutedEventArgs e)
63+
{
64+
var presenter = (FlyoutPresenter)sender;
65+
var okButton = presenter.FindDescendant<Button>(b => b.Name is "OkButton");
66+
var cancelButton = presenter.FindDescendant<Button>(b => b.Name is "CancelButton");
67+
var menuPresenter = presenter.FindDescendant<MenuFlyoutPresenter>();
68+
menuPresenter?.ItemsSource = Items;
69+
70+
_filterItemsControl = presenter.FindDescendant<TableViewFilterItemsControl>();
71+
_filterItemsControl?.TableView = TableView;
72+
_filterItemsControl?.ColumnHeader = ColumnHeader;
73+
74+
okButton?.Command = _okCommand;
75+
cancelButton?.Command = _cancelCommand;
76+
77+
presenter.Loaded -= OnPresenterLoaded;
78+
_filterItemsControl?.Initialize();
79+
80+
foreach (var item in Items.OfType<MenuFlyoutItem>())
81+
{
82+
item.Tapped += OnMenuItemTapped;
83+
}
84+
}
85+
86+
/// <summary>
87+
/// Handles the Tapped event of menu items.
88+
/// </summary>
89+
private void OnMenuItemTapped(object sender, TappedRoutedEventArgs e)
90+
{
91+
Hide();
92+
}
93+
94+
/// <summary>
95+
/// Executes the OK command, applying the filter and hiding the flyout.
96+
/// </summary>
97+
private void ExecuteOkCommand()
98+
{
99+
Hide();
100+
ColumnHeader?.ApplyFilter();
101+
}
102+
103+
/// <summary>
104+
/// Gets or sets the TableView associated with this filter menu flyout.
105+
/// </summary>
106+
public TableView? TableView { get; set; }
107+
108+
/// <summary>
109+
/// Gets or sets the TableViewColumnHeader associated with this filter menu flyout.
110+
/// </summary>
111+
public TableViewColumnHeader? ColumnHeader { get; set; }
112+
113+
/// <summary>
114+
/// Gets or sets the collection of menu items to be displayed in the filter flyout.
115+
/// </summary>
116+
public IList<MenuFlyoutItemBase> Items { get; set; }
117+
}

0 commit comments

Comments
 (0)