Skip to main content

Step 3: Enable Filter Operations

  • 5 minutes to read

This step describes how to allow users to filter rows:

  • Implement filter operations in the virtual source.
  • Enable these operations in the GridControl.

VirtualSourcesTutorialFiltering

Note

This tutorial uses the Issues Service as a sample data source.

Run Demo: Infinite Scrolling Source - Step 3 Run Demo: Paged Source - Step 3

Refer to the Enable Search Panel topic for information on how to display the Search Panel in the GridControl bound to a virtual source.

Filter Types

The Issues Service can fetch rows:

  • With a specified Priority.
  • Over a period of time (between CreatedFrom and CreatedTo).
  • With the maximum number of Votes.
public class IssueFilter {  
    public Priority? Priority { get; private set; }
    public DateTime? CreatedFrom { get; private set; }
    public DateTime? CreatedTo { get; private set; }
    public int? MinVotes { get; private set; }
}

The Step 1: Fetch Data topic demonstrates how to fetch rows without filter conditions:

[Command]
public void FetchIssues(FetchRowsAsyncArgs args) {
    args.Result = GetIssuesAsync(args);
}
async Task<FetchRowsResult> GetIssuesAsync(FetchRowsAsyncArgs args) {
    var take = args.Take ?? 30;
    var issues = await IssuesService.GetIssuesAsync(
        skip: args.Skip,
        take: take,
        sortOrder: GetIssueSortOrder(args.SortOrder),
        filter: null);

    return new FetchRowsResult(issues, hasMoreRows: issues.Length == take);
}

Allow Users to Filter Rows

  1. Create a filter converter and assign it to the DataControlBase.CriteriaConverter property. The filter converter specified in the View allows you to avoid a reference to the DevExpress.Data namespace in your ViewModel.

    <dxg:GridControl CriteriaConverter="{local:IssueFilterConverter}"/>
    

    If you can reference the DevExpress.Data namespace in your ViewModel, create a method that parses the GridControl‘s filter in the ViewModel.

  2. In the filter converter, get the GridControl‘s filter, parse it, and return an IssueFilter (a type used in the Model). A command bound to the InfiniteAsyncSource.FetchRowsCommand property uses this filter when the GridControl fetches rows.

    using System;
    using System.Linq;
    using System.Globalization;
    using System.Windows.Data;
    using System.Windows.Markup;
    using DevExpress.Data.Filtering;
    using DevExpress.Xpf.Data;
    
    public class IssueFilterConverter : MarkupExtension, IValueConverter {
        object IValueConverter.Convert(object filter, Type targetType, object parameter, CultureInfo culture) {
            return ((CriteriaOperator)filter).Match(
                binary: (propertyName, value, type) => {
                    if (propertyName == "Votes" && type == BinaryOperatorType.GreaterOrEqual)
                        return new IssueFilter(minVotes: (int)value);
                    if (propertyName == "Priority" && type == BinaryOperatorType.Equal)
                        return new IssueFilter(priority: (Priority)value);
                    if (propertyName == "Created") {
                        if (type == BinaryOperatorType.GreaterOrEqual)
                            return new IssueFilter(createdFrom: (DateTime)value);
                        if (type == BinaryOperatorType.Less)
                            return new IssueFilter(createdTo: (DateTime)value);
                    }
                    throw new InvalidOperationException();
                },
                and: filters => {
                    return new IssueFilter(
                        createdFrom: filters.Select(x => x.CreatedFrom).SingleOrDefault(x => x != null),
                        createdTo: filters.Select(x => x.CreatedTo).SingleOrDefault(x => x != null),
                        minVotes: filters.Select(x => x.MinVotes).SingleOrDefault(x => x != null),
                        priority: filters.Select(x => x.Priority).SingleOrDefault(x => x != null)
                    );
                },
                @null: default(IssueFilter)
            );
        }
        object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
        public override object ProvideValue(IServiceProvider serviceProvider) => this;
    }
    

    Tip

    The code sample above uses the FilterCriteriaMatchHelper.Match method that allows you to parse filter criteria created by the GridControl.

    The FilterCriteriaMatchHelper is an extension of the DevExpress.Xpf.Grid.v24.1.Extensions.dll library. Refer to the following path for information on how the extension’s methods work: c:\Program Files\DevExpress 24.1\XPF\DevExpress.Xpf.Grid\DevExpress.Xpf.Grid.Extensions\.

    When you specify the DataControlBase.CriteriaConverter property, the FetchAsyncArgsBase.Filter property returns a filter of the Object type. You can cast this filter to the type returned by the filter converter (IssueFilter in this tutorial).

    [Command]
    public void FetchIssues(FetchRowsAsyncArgs args) {
        args.Result = GetIssuesAsync(args);
    }
    async Task<FetchRowsResult> GetIssuesAsync(FetchRowsAsyncArgs args) {
        var take = Math.Min(args.Take ?? 30, 100);
        var issues = await IssuesService.GetIssuesAsync(
            skip: args.Skip,
            take: take,
            sortOrder: GetIssueSortOrder(args.SortOrder),
            filter: (IssueFilter)args.Filter);
    
        return new FetchRowsResult(issues, hasMoreRows: issues.Length == take);
    }
    
  3. Get a list of priorities to show them in the Priority column’s drop-down filter:

    VirtualSourcesPriorities

    [Command]
    public void GetUniqueValues(GetUniqueValuesAsyncArgs args) {
        if(args.PropertyName == "Priority") {
            var values = Enum.GetValues(typeof(Priority)).Cast<object>().ToArray();
            args.Result = Task.FromResult(values);
        } else {
            throw new InvalidOperationException();
        }
    }
    
    <dxg:GridControl CriteriaConverter="{local:IssueFilterConverter}">
        <dxg:GridControl.ItemsSource>
            <dx:InfiniteAsyncSource ElementType="{x:Type local:IssueData}"
                                    FetchRowsCommand="{Binding FetchIssuesCommand}"
                                    GetUniqueValuesCommand="{Binding GetUniqueValuesCommand}"/>
        </dxg:GridControl.ItemsSource>
        <!-- ... -->
    </dxg:GridControl>
    

    If a service or database includes a method that obtains unique values, use this method in the GetUniqueValues command.

  4. Allow users to filter GridControl rows by the Priority column:

    <dxg:GridColumn FieldName="Priority" 
                    AllowedBinaryFilters="Equals" 
                    FilterPopupMode="List"/>
    

    VirtualSourcesFilteringVotes

  5. Allow users to filter GridControl rows by the Votes column:

    • Set the ColumnBase.AllowedBinaryFilters property to GreaterOrEqual to allow users to show rows with votes that are greater than or equal to an input value.
    • Set the ColumnBase.FilterPopupMode property to Excel to enable a drop-down filter that allows users to create the GreaterOrEqual criteria.
    <dxg:GridColumn FieldName="Votes" 
                    AllowedBinaryFilters="GreaterOrEqual" 
                    FilterPopupMode="Excel"/>
    

    VirtualSourcesFilteringVotes

  6. Allow users to filter GridControl rows by the Created column:

    <dxg:GridColumn FieldName="Created" 
                    AllowedDateTimeFilters="SingleDateRange" 
                    FilterPopupMode="DateSmart"/>
    

    VirtualSourcesFilteringCreated

Continue or Review