Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/docs/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ Show how many rows match each filter value:
<tv:TableView ShowFilterItemsCount="True" />
```

## Applying filters as they change

By default the filter flyout applies a column's filter when OK is pressed. To apply it as soon as an item is checked or unchecked, or the search text changes, turn on `ApplyColumnFilterImmediately`. The flyout then drops its OK and Cancel buttons, and closing it keeps the filter:

```xml
<tv:TableView ApplyColumnFilterImmediately="True" />
```

## Filtering programmatically

Add filter descriptions to `TableView.FilterDescriptions`:
Expand Down
37 changes: 37 additions & 0 deletions src/Controls/TableViewFilterItemsControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace WinUI.TableView.Controls;
public partial class TableViewFilterItemsControl : UserControl
{
private bool _canSetState = true;
private bool _isClearingSearchBox;
private bool _isUpdatingSelectAllCheckBox;

/// <summary>
/// Initializes a new instance of the <see cref="TableViewFilterItemsControl"/> class.
Expand Down Expand Up @@ -49,12 +51,32 @@ internal async void Initialize()
/// </summary>
internal void ClearSearchBox()
{
// The flyout clears its search when it closes; that isn't the user changing the filter, so it mustn't
// undo a filter that was applied from the search.
_isClearingSearchBox = true;
searchBox?.Text = string.Empty;
_isClearingSearchBox = false;
}

private void OnSearchBoxTextChanged(object sender, TextChangedEventArgs e)
{
FilterItems = TableView?.FilterHandler?.GetFilterItems(ColumnHeader?.Column!, searchBox!.Text);

if (!_isClearingSearchBox)
{
ApplyFilterIfImmediate();
}
}

/// <summary>
/// Applies the filter as it stands, as OK would, when <see cref="TableView.ApplyColumnFilterImmediately"/> is on.
/// </summary>
private void ApplyFilterIfImmediate()
{
if (TableView?.ApplyColumnFilterImmediately is true)
{
ColumnHeader?.ApplyFilter();
}
}

/// <summary>
Expand All @@ -76,7 +98,14 @@ private void OnSearchBoxKeyDown(object sender, KeyRoutedEventArgs e)
/// </summary>
private void OnSelectAllCheckBoxCheckChanged(object sender, RoutedEventArgs e)
{
// The checkbox also follows the items (SetSelectAllCheckBoxState); only a click on it changes the filter.
if (_isUpdatingSelectAllCheckBox)
{
return;
}

SetFilterItemsState(selectAllCheckBox.IsChecked is true);
ApplyFilterIfImmediate();
}

/// <summary>
Expand All @@ -90,9 +119,11 @@ internal void SetSelectAllCheckBoxState()
}


_isUpdatingSelectAllCheckBox = true;
selectAllCheckBox.IsChecked = FilterItems?.All(x => x.IsSelected) ?? false ? true
: FilterItems?.All(x => !x.IsSelected) ?? false ? false
: null;
_isUpdatingSelectAllCheckBox = false;
}

/// <summary>
Expand Down Expand Up @@ -145,6 +176,12 @@ private void DetachPropertyChangedHandlers()
private void OnFilterItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
SetSelectAllCheckBoxState();

// SetFilterItemsState changes every item at once and applies once itself.
if (_canSetState && e.PropertyName is nameof(TableViewFilterItem.IsSelected))
{
ApplyFilterIfImmediate();
}
}

/// <summary>
Expand Down
16 changes: 16 additions & 0 deletions src/TableView.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ public partial class TableView
/// </summary>
public static readonly DependencyProperty ShowFilterItemsCountProperty = DependencyProperty.Register(nameof(ShowFilterItemsCount), typeof(bool), typeof(TableView), new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="ApplyColumnFilterImmediately"/> dependency property.
/// </summary>
public static readonly DependencyProperty ApplyColumnFilterImmediatelyProperty = DependencyProperty.Register(nameof(ApplyColumnFilterImmediately), typeof(bool), typeof(TableView), new PropertyMetadata(false));


/// <summary>
/// Identifies the <see cref="ForceRowOrCellSelectionOnContextRequested"/> dependency property.
Expand Down Expand Up @@ -412,6 +417,17 @@ public bool ShowFilterItemsCount
set => SetValue(ShowFilterItemsCountProperty, value);
}

/// <summary>
/// Gets or sets a value that indicates whether a column's filter applies as soon as it changes in the filter
/// flyout (an item is checked or unchecked, or the search text changes) instead of when OK is pressed.
/// The flyout then has no OK and Cancel buttons; closing it keeps the filter.
/// </summary>
public bool ApplyColumnFilterImmediately
{
get => (bool)GetValue(ApplyColumnFilterImmediatelyProperty);
set => SetValue(ApplyColumnFilterImmediatelyProperty, value);
}

/// <summary>
/// Gets or sets a value indicating whether the drag selection rectangle is shown during cell drag selection.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions src/TableViewFilterMenuFlyout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace WinUI.TableView;
public partial class TableViewFilterMenuFlyout : Flyout
{
private TableViewFilterItemsControl? _filterItemsControl;
private FrameworkElement? _buttonsPanel;
private readonly StandardUICommand _okCommand = new() { Label = TableViewLocalizedStrings.Ok };
private readonly StandardUICommand _cancelCommand = new() { Label = TableViewLocalizedStrings.Cancel };

Expand Down Expand Up @@ -44,6 +45,15 @@ protected override Control CreatePresenter()
private void OnOpening(object? sender, object e)
{
_filterItemsControl?.Initialize();
UpdateButtonsVisibility();
}

/// <summary>
/// Hides OK and Cancel when the filter applies as it changes: there's nothing left for them to do.
/// </summary>
private void UpdateButtonsVisibility()
{
_buttonsPanel?.Visibility = TableView?.ApplyColumnFilterImmediately is true ? Visibility.Collapsed : Visibility.Visible;
}

/// <summary>
Expand Down Expand Up @@ -71,6 +81,8 @@ private void OnPresenterLoaded(object sender, RoutedEventArgs e)

okButton?.Command = _okCommand;
cancelButton?.Command = _cancelCommand;
_buttonsPanel = okButton?.Parent as FrameworkElement;
UpdateButtonsVisibility();

presenter.Loaded -= OnPresenterLoaded;
_filterItemsControl?.Initialize();
Expand Down