Filtering in WinUI DataGrid
21 Jun 202224 minutes to read
Filtering is the process of retrieving the values from the collection which satisfy the specified condition. In the SfDataGrid the filtering can be applied though the UI as well as the programmatic filters.
Programmatic filtering
DataGrid allows you to filter the data programmatically in below ways,
- Through View Predicate
- Through Column Filter
View Filtering
View filtering can be achieved by setting SfDataGrid.View.Filter delegate. You can refresh the view by calling SfDataGrid.View.RefreshFilter method.
Here, FilterRecords delegate filters the data based on Country name. FilterRecords delegate is assigned to SfDataGrid.View.Filter
predicate to filter Country column. After that, SfDataGrid.View.RefreshFilter
method is called to refresh the records. If the record satisfies the filter conditions, true
will be returned. Else false
is returned.
public bool FilterRecords(object o)
{
string filterText = "Germany";
var item = o as OrderInfo;
if (item != null)
{
if (item.Country.Equals(filterText))
return true;
}
return false;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (sfDataGrid != null && sfDataGrid.View != null)
{
sfDataGrid.View.Filter = FilterRecords;
sfDataGrid.View.RefreshFilter();
}
}
Column Filtering
Column filtering is achieved by using GridColumn.FilterPredicates property and adding FilterPredicate to it.
Here, OrderID column is filtered for the data which has OrderID as 1005.
sfDataGrid.Columns["OrderID"].FilterPredicates.Add(new FilterPredicate() { FilterType = FilterType.Equals, FilterValue = "1005" });
Filter Behavior
- StringTyped - Records are filtered without considering the type and it takes FilterValue type as string.
-
StronglyTyped - Records are filtered by considering the
FilterValue
underlying type.
Improving performance while adding multiple FilterPredicates to the column in loop
You can improve the performance of filtering by suspending the data operation while adding FilterPredicates
to the column for bulk updates by calling SfDataGrid.View.BeginInit and SfDataGrid.View.EndInit method, before and after the data operation.
private ObservableCollection<string> filterValues;
/// <summary>
/// Get or set the FilterValues
/// </summary>
public ObservableCollection<string> FilterValues
{
get { return filterValues; }
set { filterValues = value; }
}
private void ApplyFilterPredicate(object sender, RoutedEventArgs e)
{
var gridColumn = this.sfDataGrid.Columns["OrderID"];
sfDataGrid.View.BeginInit();
foreach (var filterValue in FilterValues)
{
gridColumn.FilterPredicates.Add(new FilterPredicate()
{
FilterType = FilterType.Equals,
FilterValue = filterValue,
FilterBehavior = FilterBehavior.StronglyTyped,
FilterMode = ColumnFilter.Value,
PredicateType = PredicateType.Or,
IsCaseSensitive = true
});
}
sfDataGrid.View.EndInit();
}
Clear Filtering
SfDataGrid allows you to clear the filters by clearing the filter predicates. This is achieved by invoking the following methods.
- SfDataGrid.ClearFilters - Clears filters for all the columns programmatically.
-
SfDataGrid.ClearFilter(String columnName) - Clears the filter for particular column that has the columnName as
MappingName
. - SfDataGrid.ClearFilter(GridColumn column) - Clears the filter for particular column alone.
this.sfDataGrid.ClearFilters();
this.sfDataGrid.ClearFilter("OrderID");
this.sfDataGrid.ClearFilter(this.sfDataGrid.Columns[0]);
Excel like UI Filtering
SfDataGrid provides excel like filtering UI and also advanced filter UI to filter the data easily. UI filtering can be enabled by setting SfDataGrid.AllowFiltering property to true
, where you can open filter UI by clicking the Filter icon in column header and filter the records.
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AllowFiltering="True"
AutoGenerateColumns="True"
ItemsSource="{Binding Orders}" />
sfDataGrid.AllowFiltering = true;
You can enable/disable filtering for particular column by setting GridColumn.AllowFiltering property.
<dataGrid:GridTextColumn AllowFiltering="True"
MappingName="OrderID" />
sfDataGrid.Columns["OrderID"].AllowFiltering = true;
NOTE
GridColumn.AllowFiltering
has higher priority thanSfDataGrid.AllowFiltering
property.
Built-in UI Views
SfDataGrid filter UI comprises of two different UIs.
-
Checkbox Filter UI - Provides excel like filter interface with list of check box’s.
-
Advanced Filter UI - Provides advanced filter options to filter the data.
By default, both CheckboxFilter and Advanced Filter are loaded while opening the filter pop-up. You can switch between AdvancedFilter
and CheckboxFilter
by using AdvancedFilter button in the UI View.
SfDataGrid with Checkbox Filter View:
SfDataGrid with Advanced Filter View:
Choose between built-in UI Views
SfDataGrid lets you to customize the UI Views displayed for particular column or grid using FilterMode property in GridFilterControl.
Below are the options,
-
CheckboxFilter
– Displays only Checkbox filter View. -
AdvancedFilter
– Displays only Advanced filter View. - Both – Displays both filters Views.
Changing filter UI View for Grid
Filter UI view can be changed for all the columns in grid by changing FilterMode
in GridFilterControl
by writing style and assign it to SfDataGrid.FilterPopupStyle.
<Style x:Key="filterControlStyle" TargetType="dataGrid:GridFilterControl">
<Setter Property="FilterMode" Value="AdvancedFilter" />
</Style>
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AllowFiltering="True"
AutoGenerateColumns="True"
FilterPopupStyle="{StaticResource filterControlStyle}"
ItemsSource="{Binding Orders}"/>
Changing filter UI View for columns
Filter UI view can be changed for the particular column by changing FilterMode
in GridFilterControl
by writing style and assign it to GridColumn.FilterPopupStyle.
<Style x:Key="filterControlStyle" TargetType="dataGrid:GridFilterControl">
<Setter Property="FilterMode" Value="AdvancedFilter" />
</Style>
<dataGrid:GridTextColumn MappingName="OrderID"
FilterPopupStyle="{StaticResource filterControlStyle}" />
Changing filter UI View programmatically
You can change FilterMode
programmatically by using FilterItemsPopulating event.
this.sfDataGrid.FilterItemsPopulating += sfDataGrid_FilterItemsPopulating;
void sfDataGrid_FilterItemsPopulating(object sender, Syncfusion.UI.Xaml.DataGrid.GridFilterItemsPopulatingEventArgs e)
{
if (e.Column.MappingName == "OrderID")
e.FilterControl.FilterMode = FilterMode.AdvancedFilter;
}
Setting Default Filter popup style for particular column
You can skip the GridFilterControl
styling for particular column from SfDataGrid.FilterPopupStyle
by setting GridColumn.FilterPopupStyle
to null
.
<Page.Resources>
<Style x:Key="filterControlStyle" TargetType="dataGrid:GridFilterControl">
<Setter Property="FilterMode" Value="AdvancedFilter" />
</Style>
</Page.Resources>
<dataGrid:SfDataGrid Name="sfDataGrid"
AllowFiltering="True"
FilterPopupStyle="{StaticResource filterControlStyle}"
ItemsSource="{Binding Orders}">
<dataGrid:SfDataGrid.Columns>
<dataGrid:GridTextColumn FilterPopupStyle="{x:Null}" MappingName="OrderID" />
</dataGrid:SfDataGrid.Columns>
</dataGrid:SfDataGrid>
this.sfDataGrid.Columns["OrderID"].FilterPopupStyle = null;
Here, advanced filter will be loaded for all the columns in grid except OrderID column since GridColumn.FilterPopupStyle
is set as null
for OrderID column. So both checkbox filter and advanced filter (default style) will be loaded for OrderID column.
Advanced Filter UI
Advanced filter UI provides multiple filter options to filter the data easily. Filter menu options are loaded based on Advanced filter type by automatically detecting the underlying date type.
Below are the built-in filter types supported.
- TextFilters – Loads various menu options to filter the display text effectively.
- NumberFilters – Loads various menu options to filter the numeric data.
- DateFilters – Loads various menu options and SfCalendarDatePicker to filter DateTimeOffset type column.
Text Filters | Number Filters | Date Filters |
---|---|---|
When the string value is bounded to the
or the items source is
,then TextFilters are loaded in
.
|
When integer, double, short, decimal, byte or long are bound to the
then NumberFilters are loaded in
.
|
When the DateTimeOffset type value is bound to the
then DateFilters are loaded in
.
|
Filter menu options
|
Filter menu options
|
Filter menu options
|
NOTE
Null
andNot Null
options are available only when AllowBlankFilters is set toTrue
.- If the column is GridUnboundColumn, then
TextFilters
will be loaded.
Changing Advanced Filter type
FilterBehavior determines the Advanced filter type loaded in GridFilterControl
. By using FilterBehavior
, you can change Advanced filter type.
-
StringTyped
-TextFilters
will be loaded inAdvancedFilterControl
. -
StronglyTyped
– Advanced filter type is automatically detected based on underlying data type.
<dataGrid:SfDataGrid.Columns>
<dataGrid:GridTextColumn MappingName="OrderID" FilterBehavior="StringTyped"/>
</dataGrid:SfDataGrid.Columns>
sfDataGrid.Columns["OrderID"].FilterBehavior = FilterBehavior.StringTyped;
Advanced filter type can be changed programmatically by using FilterItemsPopulating
event also.
this.sfDataGrid.FilterItemsPopulating += sfDataGrid_FilterItemsPopulating;
void sfDataGrid_FilterItemsPopulating(object sender, Syncfusion.UI.Xaml.DataGrid.GridFilterItemsPopulatingEventArgs e)
{
if (e.Column.MappingName != "OrderID")
return;
e.FilterControl.AdvancedFilterType = AdvancedFilterType.TextFilter;
e.FilterControl.SetColumnDataType(typeof(string));
e.FilterControl.AscendingSortString = GridLocalizationResourceAccessor.Instance.GetLocalizedStringResource("SortStringAscending");
e.FilterControl.DescendingSortString = GridLocalizationResourceAccessor.Instance.GetLocalizedStringResource("SortStringDescending");
}
Case Sensitive
By default, casing is not considered while filtering. Because, filter predicates will be created with IsCaseSensitive
as false
. If you want to filter the records with IsCaseSensitive
as true
, you need to click case sensitive button present in Advanced Filter.
Performance tips
GridFilterControl’s
loading performance can be increased by setting FilterMode
as AdvancedFilter
and CanGenerateUniqueItems as False
. Because a textbox is loaded instead of AdvancedFilter ComboBox that allows you to manually enter text for filtering.
<Style x:Key="advancedFilterControlStyle" TargetType="dataGrid:AdvancedFilterControl">
<Setter Property="CanGenerateUniqueItems" Value="False" />
</Style>
<Style x:Key="filterControlStyle" TargetType="dataGrid:GridFilterControl">
<Setter Property="FilterMode" Value="AdvancedFilter" />
<Setter Property="AdvancedFilterStyle" Value="{StaticResource advancedFilterControlStyle}" />
</Style>
<dataGrid:SfDataGrid x:Name="sfDataGrid"
AllowFiltering="True"
AutoGenerateColumns="True"
FilterPopupStyle="{StaticResource filterControlStyle}"
ItemsSource="{Binding Orders}"/>
By default, CanGenerateUniqueItems
is True
. So all the unique items in the column are loaded in the AdvancedFilter ComboBox that allows you to select the value easily from the combo box and filter it.
Filtering null values
To filter the null values, you need to set AllowBlankFilters
property as True
. So null
values will be included in filter items list. If you want to exclude the null values from filter items list, you need to set AllowBlankFilters
as False
.
<dataGrid:GridTextColumn AllowBlankFilters="True" MappingName="Country" />
sfDataGrid.Columns["Country"].AllowBlankFilters = true;
Checkbox Filter with AllowBlankFilters
as True
Advanced Filter with AllowBlankFilters
as True
Instant Filtering
By default, filters are applied to the columns when OK button is clicked in UI filtering. If you want to update the filters immediately whenever update in filter popup, you need to set ImmediateUpdateColumnFilter as True
.
<dataGrid:GridTextColumn ImmediateUpdateColumnFilter="True" MappingName="OrderID" />
sfDataGrid.Columns["OrderID"].ImmediateUpdateColumnFilter = true;
Here, the OK and Cancel buttons are unavailable and Done button is available to just close the popup.
Checkbox Filter with ImmediateUpdateColumnFilter
is True
Advanced Filter with ImmediateUpdateColumnFilter
is True
NOTE
In Checkbox Filter, the
SelectAll
option is not reflected in the filter updates ifImmediateUpdateColumnFilter
isTrue
.
Events
SfDataGrid provides the following events for filtering.
FilterChanging event
FilterChanging event is raised while applying filters to a particular column. You can use this event to change the FilterPredicates, FilterType and FilterBehavior.
this.sfDataGrid.FilterChanging += sfDataGrid_FilterChanging;
void sfDataGrid_FilterChanging(object sender, GridFilterEventArgs e)
{
}
FilterChanged event
FilterChanged event is raised after filter is applied. You can use this event to get filtered records.
this.sfDataGrid.FilterChanged += sfDataGrid_FilterChanged;
void sfDataGrid_FilterChanged(object sender, GridFilterEventArgs e)
{
}
FilterItemsPopulating event
FilterItemsPopulating event is raised while populating the filter list items in GridFilterControl. You can change GridFilterControl
properties by using this event.
this.sfDataGrid.FilterItemsPopulating += sfDataGrid_FilterItemsPopulating;
void sfDataGrid_FilterItemsPopulating(object sender, Syncfusion.UI.Xaml.DataGrid.GridFilterItemsPopulatingEventArgs e)
{
}
FilterItemsPopulated event
FilterItemsPopulated event is raised after filter list items are populated. You can change GridFilterItemsPopulatedEventArgs.ItemSource by using this event.
this.sfDataGrid.FilterItemsPopulated += sfDataGrid_FilterItemsPopulated;
void sfDataGrid_FilterItemsPopulated(object sender, GridFilterItemsPopulatedEventArgs e)
{
}
Getting the filtered records
You can get the filtered records from View in FilterChanged
event. When filter is applied, the filtered records are available in View.Records.
this.sfDataGrid.FilterChanged += sfDataGrid_FilterChanged;
void sfDataGrid_FilterChanged(object sender, GridFilterEventArgs e)
{
//OrderInfo is Model Class
ObservableCollection<OrderInfo> order = new ObservableCollection<OrderInfo>();
// Get filtered records
var records = (sender as SfDataGrid).View.Records;
foreach (RecordEntry record in records)
order.Add(record.Data as OrderInfo);
}
Show image in CheckBoxFilterControl instead of image path
By default, in SfDataGrid image path is shown inside the CheckBoxFilterControl instead of image but you can show the image in CheckBoxFilterControl
by setting CheckboxFilterControl.ItemTemplate as like below.
<dataGrid:GridImageColumn MappingName="Flag" HeaderText="Country" ImageHeight="50" ImageWidth="50" TextAlignment="Center">
<dataGrid:GridImageColumn.FilterPopupStyle>
<Style TargetType="dataGrid:GridFilterControl">
<Setter Property="CheckboxFilterStyle">
<Setter.Value>
<Style TargetType="dataGrid:CheckboxFilterControl">
<Setter Property="Background" Value="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"/>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<CheckBox Margin="4"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Content="{Binding}"
FontWeight="{Binding FontWeight,RelativeSource={RelativeSource Self}}"
Foreground="{Binding Foreground,RelativeSource={RelativeSource Self}}"
IsChecked="{Binding IsSelected, Mode=TwoWay}">
<CheckBox.ContentTemplate>
<DataTemplate>
<Image Source="{Binding Path=ActualValue}" HorizontalAlignment="Left" Height="25"/>
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</dataGrid:GridImageColumn.FilterPopupStyle>
</dataGrid:GridImageColumn>
Functionality Customization
Loading the Text Filters for the column having Number or Date value as underlying type
If you want to use the Text Filters for the column that has number or date value as underlying type, you need to set FilterBehavior
property of the GridColumn
as StringTyped
. This loads the Text Filters instead of Number or Date Filters.
<dataGrid:GridTextColumn MappingName="OrderID" FilterBehavior="StringTyped"/>
You can achieve this programmatically by using FilterItemsPopulating
event also.
this.sfDataGrid.FilterItemsPopulating += sfDataGrid_FilterItemsPopulating;
void sfDdataGrid_FilterItemsPopulating(object sender, Syncfusion.UI.Xaml.Grid.GridFilterItemsPopulatingEventArgs e)
{
if (e.Column.MappingName == "OrderID")
{
e.FilterControl.AdvancedFilterType = AdvancedFilterType.TextFilter;
e.FilterControl.SetColumnDataType(typeof(string));
e.FilterControl.AscendingSortString = GridLocalizationResourceAccessor.Instance.GetLocalizedStringResource("SortStringAscending");
e.FilterControl.DescendingSortString = GridLocalizationResourceAccessor.Instance.GetLocalizedStringResource("SortStringDescending");
}
}
Changing AdvancedFilter type while loading dynamic ItemsSource
By default, TextFilters
will be loaded for the columns if ItemsSource
is dynamic. If you want to load Number Filters or Date Filters based on column values, you need to use ColumnMemberType property.
this.sfDataGrid.Columns["OrderID"].ColumnMemberType = typeof(double?);
You can achieve this by using FilterItemsPopulating
event also. But in this case, Nullable
type values will not be filtered in advanced filtering. So you need to set ColumnMemberType
.
Customizing Excel like Filter ItemsSource
When you want to restrict some data from filtering, you need to customize the GridFilterControl ItemsSource
by using FilterItemsPopulated
event. Here, FilterElement which has ActualValue
as 1005 is removed from ItemsSource
.
this.sfDataGrid.FilterItemsPopulated += sfDataGrid_FilterItemsPopulated;
void sfDataGrid_FilterItemsPopulated(object sender, GridFilterItemsPopulatedEventArgs e)
{
if (e.Column.MappingName == "OrderID")
{
var itemsSource = e.ItemsSource as List<FilterElement>;
//Get the FilterElement to Remove from itemsSource.
var filterElement = itemsSource.FirstOrDefault(items => items.ActualValue.Equals(1005));
//Remove the FilterElement from itemsSource.
itemsSource.Remove(filterElement);
}
}
Likewise, FilterElement
also can be changed.
Customizing Filter predicates
If you want to customize the filter predicates, you need to use FilterChanging event. Here, FilterValue is changed according to some conditions.
this.sfDataGrid.FilterChanging += sfDataGrid_FilterChanging;
void sfDataGrid_FilterChanging(object sender, GridFilterEventArgs e)
{
if (e.FilterPredicates == null || e.Column.MappingName != "CustomerID" || e.FilterPredicates.Count == 0)
return;
if (e.FilterPredicates[0].FilterValue.Equals("ALFKI"))
e.FilterPredicates[0].FilterValue = "ANATR";
}
Appearance customization
GridFilterControl is derived from ContentControl
and has its own structure. This structure is customized using the properties SfDataGrid.FilterPopupStyle and SfDataGrid.FilterPopupTemplate for all the columns in grid.
When you need to change the appearance of the GridFilterControl
for a particular column, GridColumn.FilterPopupStyle and GridColumn.FilterPopupTemplate properties are used.
Collapsing Sort Options in GridFilterControl
Sort Options can be collapsed by setting SortOptionVisibility property in GridFilterControl
.
<Style TargetType="dataGrid:GridFilterControl" x:Key="gridFilterControlStyle">
<Setter Property="SortOptionVisibility" Value="Collapsed"/>
</Style>
<dataGrid:SfDataGrid x:Name="dataGrid"
AllowFiltering="True"
AutoGenerateColumns="True"
FilterPopupStyle="{StaticResource gridFilterControlStyle}"
ItemsSource="{Binding Orders}"/>
Customizing Sort Options text
Sort Options text can be customized by using AscendingSortString and DescendingSortString properties in GridFilterControl
.
this.sfDataGrid.FilterItemsPopulating += sfDataGrid_FilterItemsPopulating;
void sfDataGrid_FilterItemsPopulating(object sender, GridFilterItemsPopulatingEventArgs e)
{
if(e.Column.MappingName == "CustomerName")
{
e.FilterControl.AscendingSortString = "Sort Ascending";
e.FilterControl.DescendingSortString = "Sort Descending";
}
}
Customize the FilterPopup size using GridFilterControl style
You can customize the FilterPopup size using FilterPopupHeight property by writing style of TargetType as GridFilterControl
.
<Page.Resources>
<Style TargetType="dataGrid:GridFilterControl">
<Setter Property="FontSize" Value="14" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FilterPopupHeight" Value="620" />
</Style>
</Page.Resources>
Changing filter icon style after applying filters
You can change the filter icon style by editing the FilterToggleButton style. In FilterToggleButton
style, you can see Filtered
and UnFiltered
VisualStates. In that, you can change PathFillColor
for FilterToggleButton
.
xmlns:grid="using:Syncfusion.UI.Xaml.Grids"
<Page.Resources>
<Style TargetType="grid:FilterToggleButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="grid:FilterToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FilterStates">
<VisualState x:Name="Filtered">
<Storyboard BeginTime="0">
<ObjectAnimationUsingKeyFrames BeginTime="0"
Duration="1"
Storyboard.TargetName="PART_FilterToggleButtonIndicator"
Storyboard.TargetProperty="Data">
<DiscreteObjectKeyFrame KeyTime="0" Value="M2.1299944,9.9798575L55.945994,9.9798575 35.197562,34.081179 35.197562,62.672859 23.428433,55.942383 23.428433,33.52121z M1.3001332,0L56.635813,0C57.355887,0,57.935946,0.5891428,57.935946,1.3080959L57.935946,2.8258877C57.935946,3.5448422,57.355887,4.133985,56.635813,4.133985L1.3001332,4.133985C0.58005941,4.133985,-2.3841858E-07,3.5448422,0,2.8258877L0,1.3080959C-2.3841858E-07,0.5891428,0.58005941,0,1.3001332,0z" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimation BeginTime="0"
Duration="00:00:01"
Storyboard.TargetName="PathFillColor"
Storyboard.TargetProperty="Color"
To="Red" />
</Storyboard>
</VisualState>
<VisualState x:Name="UnFiltered">
<Storyboard BeginTime="0">
<ObjectAnimationUsingKeyFrames BeginTime="0"
Duration="1"
Storyboard.TargetName="PART_FilterToggleButtonIndicator"
Storyboard.TargetProperty="Data">
<DiscreteObjectKeyFrame KeyTime="0" Value="M0,0 L118.49799,0 L72.811813,53.068943 L72.811813,116.02525 L46.897243,101.20534 L46.897243,51.835941 z" />
</ObjectAnimationUsingKeyFrames>
<ColorAnimation BeginTime="0"
Duration="00:00:01"
Storyboard.TargetName="PathFillColor"
Storyboard.TargetProperty="Color"
To="Gray" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Background="Transparent">
<Path Name="PART_FilterToggleButtonIndicator"
Margin="{TemplateBinding Margin}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Data="M0,0 L118.49799,0 L72.811813,53.068943 L72.811813,116.02525 L46.897243,101.20534 L46.897243,51.835941 z"
Stretch="Fill">
<Path.Fill>
<SolidColorBrush x:Name="PathFillColor" Color="Gray" />
</Path.Fill>
</Path>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
When you apply above style to FilterToggleButton
, FilterIcon changes from Default to Gray and to Red when filtering is applied. When you clear it, it changes from Red to Gray and to default style.