Custom Filtering Controls

As a developer, you are not limited to the default filtering user interface provided by RadGridView when in Popup filtering mode. After the introduction of the Custom Filtering Controls feature, you can easily craft any filtering control that you like.

The example in this article produces the following result

RadGridView for WPF Custom Filtering Control

Building a Custom Filtering Control

In order to be able to communicate with RadGridView, your custom filtering control will have to implement the IFilteringControl interface. This interface allows RadGridView to communicate with your control. Let’s take a look at the interface:

/// <summary> 
/// Provides functionality required by all filtering components. 
/// </summary> 
public interface IFilteringControl 
{ 
    /// <summary> 
    /// Prepares the component for the column it will service. 
    /// </summary> 
    /// <param name="column">The column to prepare for.</param> 
    void Prepare(GridViewColumn column); 
 
    /// <summary> 
    /// Gets a value indicating whether the filtering is active. 
    /// </summary> 
    bool IsActive { get; set; } 
} 
''' <summary> 
''' Provides functionality required by all filtering components. 
''' </summary> 
Public Interface IFilteringControl 
    ''' <summary> 
    ''' Prepares the component for the column it will service. 
    ''' </summary> 
    ''' <param name="column">The column to prepare for.</param> 
    Sub Prepare(ByVal column As GridViewColumn) 
 
    ''' <summary> 
    ''' Gets a value indicating whether the filtering is active. 
    ''' </summary> 
    Property IsActive() As Boolean 
End Interface 

The Prepare method is called each time the control is about to be shown (when the user clicks the funnel in the header cell). If you do not need to change anything between two consecutive times when the filtering UI is shown, there wouldn’t be much inside this method’s body. The IsActive property provides means of “filling up” the funnel when the column is filtered. Along with the IsActive CLR property that is part of the interface, you will need to add an IsActive DependencyProperty to back the CLR property.

Next, you will have to decide what UI elements your custom filtering control will display and define them in its XAML file. When the user interacts with these UI elements you will have to react and perfrom the actual filtering. Whether you will use event handlers or the MVVM pattern is up to you and is a decision which is beyond the scope if this article. Once you have reacted to an user action you will need to filter RadGridView programmatically. Basically, to filter RadGridView you need to add an IFilterDescriptor to its FilterDescriptors collection. To clear this filter, you need to remove the IFilterDescriptor from the FilterDescriptors collection. Filtering RadGridView programmactically is explained in great detail in this article.

Here is an example of a custom filtering control that displays two date time pickers:

<Border x:Name="LayoutRoot" BorderThickness="1" BorderBrush="#FF8A929E" Padding="5" Background="#FFDFE2E5"> 
  <Grid> 
    <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="120"/> 
      <ColumnDefinition Width="120"/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <TextBlock Grid.Column="0" Grid.Row="0" Margin="2">From Date:</TextBlock> 
    <TextBlock Grid.Column="1" Grid.Row="0" Margin="2">To Date:</TextBlock> 
    <telerik:RadDatePicker Name="fromDatePicker" Grid.Column="0" Grid.Row="1" Margin="2"/> 
    <telerik:RadDatePicker Name="toDatePicker" Grid.Column="1" Grid.Row="1" Margin="2"/> 
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center"> 
      <telerik:RadButton Name="filterButton" Content="Filter" Click="OnFilter" Margin="2" Width="80"/> 
      <telerik:RadButton Name="clearButton" Content="Clear" Click="OnClear" Margin="2" Width="80"/> 
    </StackPanel> 
  </Grid> 
</Border> 

/// <summary> 
/// FromDateToDateFilterControl 
/// </summary> 
public partial class FromDateToDateFilterControl : System.Windows.Controls.UserControl, IFilteringControl 
{ 
    private GridViewBoundColumnBase column; 
    private CompositeFilterDescriptor compositeFilter; 
    private Telerik.Windows.Data.FilterDescriptor fromFilter; 
    private Telerik.Windows.Data.FilterDescriptor toFilter; 
 
    /// <summary> 
    /// Gets or sets a value indicating whether the filtering is active. 
    /// </summary> 
    public bool IsActive 
    { 
        get { return (bool)GetValue(IsActiveProperty); } 
        set { SetValue(IsActiveProperty, value); } 
    } 
 
    /// <summary> 
    /// Identifies the <see cref="IsActive"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty IsActiveProperty = 
        DependencyProperty.Register( 
            "IsActive", 
            typeof(bool), 
            typeof(FromDateToDateFilterControl), 
            new System.Windows.PropertyMetadata(false)); 
 
    [TypeConverter(typeof(DateTimeTypeConverter))] 
    public DateTime FromDate 
    { 
        get { return this.fromDatePicker.SelectedDate.GetValueOrDefault(DateTime.MinValue); } 
        set { this.fromDatePicker.SelectedDate = value; } 
    } 
 
    [TypeConverter(typeof(DateTimeTypeConverter))] 
    public DateTime ToDate 
    { 
        get { return this.toDatePicker.SelectedDate.GetValueOrDefault(DateTime.MaxValue); } 
        set { this.toDatePicker.SelectedDate = value; } 
    } 
 
    public RadDatePicker FromPicker 
    { 
        get { return this.fromDatePicker; } 
    } 
 
    public RadDatePicker ToPicker 
    { 
        get { return this.toDatePicker; } 
    } 
 
    public FromDateToDateFilterControl() 
    { 
        InitializeComponent(); 
    } 
 
    public void Prepare(Telerik.Windows.Controls.GridViewColumn column) 
    { 
        this.column = column as GridViewBoundColumnBase; 
        if (this.column == null) 
        { 
            return; 
        } 
 
        if (this.compositeFilter == null) 
        { 
            this.CreateFilters(); 
        } 
 
        this.fromFilter.Value = this.FromDate; 
        this.toFilter.Value = this.ToDate; 
    } 
 
    private void CreateFilters() 
    { 
        string dataMember = this.column.DataMemberBinding.Path.Path; 
 
        this.compositeFilter = new CompositeFilterDescriptor(); 
 
        this.fromFilter = new Telerik.Windows.Data.FilterDescriptor(dataMember 
            , Telerik.Windows.Data.FilterOperator.IsGreaterThanOrEqualTo 
            , null); 
        this.compositeFilter.FilterDescriptors.Add(this.fromFilter); 
 
        this.toFilter = new Telerik.Windows.Data.FilterDescriptor(dataMember 
            , Telerik.Windows.Data.FilterOperator.IsLessThanOrEqualTo 
            , null); 
        this.compositeFilter.FilterDescriptors.Add(this.toFilter); 
    } 
 
    private void OnFilter(object sender, RoutedEventArgs e) 
    { 
        this.fromFilter.Value = this.FromDate; 
        this.toFilter.Value = this.ToDate; 
 
        if (!this.column.DataControl.FilterDescriptors.Contains(this.compositeFilter)) 
        { 
            this.column.DataControl.FilterDescriptors.Add(this.compositeFilter); 
        } 
 
        this.IsActive = true; 
    } 
 
    private void OnClear(object sender, RoutedEventArgs e) 
    { 
        if (this.column.DataControl.FilterDescriptors.Contains(this.compositeFilter)) 
        { 
            this.column.DataControl.FilterDescriptors.Remove(this.compositeFilter); 
        } 
 
        this.FromDate = new DateTime(1990, 1, 1); 
        this.ToDate = new DateTime(1995, 1, 1); 
 
        this.IsActive = false; 
    } 
} 
''' <summary> 
''' FromDateToDateFilterControl 
''' </summary> 
Partial Public Class FromDateToDateFilterControl 
    Inherits System.Windows.Controls.UserControl 
    Implements IFilteringControl 
 
    Private column As GridViewBoundColumnBase 
    Private compositeFilter As CompositeFilterDescriptor 
    Private fromFilter As Telerik.Windows.Data.FilterDescriptor 
    Private toFilter As Telerik.Windows.Data.FilterDescriptor 
 
    ''' <summary> 
    ''' Gets or sets a value indicating whether the filtering is active. 
    ''' </summary> 
    Public Property IsActive() As Boolean 
        Get 
            Return DirectCast(GetValue(IsActiveProperty), Boolean) 
        End Get 
        Set(ByVal value As Boolean) 
            SetValue(IsActiveProperty, value) 
        End Set 
    End Property 
 
    ''' <summary> 
    ''' Identifies the <see cref="IsActive"/> dependency property. 
    ''' </summary> 
    Public Shared ReadOnly IsActiveProperty As DependencyProperty = DependencyProperty.Register("IsActive", GetType(Boolean), GetType(FromDateToDateFilterControl), New System.Windows.PropertyMetadata(False)) 
 
    <TypeConverter(GetType(DateTimeTypeConverter))> 
    Public Property FromDate() As Date 
        Get 
            Return Me.fromDatePicker.SelectedDate.GetValueOrDefault(Date.MinValue) 
        End Get 
        Set(ByVal value As Date) 
            Me.fromDatePicker.SelectedDate = value 
        End Set 
    End Property 
 
    <TypeConverter(GetType(DateTimeTypeConverter))> 
    Public Property ToDate() As Date 
        Get 
            Return Me.toDatePicker.SelectedDate.GetValueOrDefault(Date.MaxValue) 
        End Get 
        Set(ByVal value As Date) 
            Me.toDatePicker.SelectedDate = value 
        End Set 
    End Property 
 
    Public ReadOnly Property FromPicker() As RadDatePicker 
        Get 
            Return Me.fromDatePicker 
        End Get 
    End Property 
 
    Public ReadOnly Property ToPicker() As RadDatePicker 
        Get 
            Return Me.toDatePicker 
        End Get 
    End Property 
 
    Public Sub New() 
        InitializeComponent() 
    End Sub 
 
    Public Sub Prepare(ByVal column As Telerik.Windows.Controls.GridViewColumn) 
        Me.column = TryCast(column, GridViewBoundColumnBase) 
        If Me.column Is Nothing Then 
            Return 
        End If 
 
        If Me.compositeFilter Is Nothing Then 
            Me.CreateFilters() 
        End If 
 
        Me.fromFilter.Value = Me.FromDate 
        Me.toFilter.Value = Me.ToDate 
    End Sub 
 
    Private Sub CreateFilters() 
        Dim dataMember As String = Me.column.DataMemberBinding.Path.Path 
 
        Me.compositeFilter = New CompositeFilterDescriptor() 
 
        Me.fromFilter = New Telerik.Windows.Data.FilterDescriptor(dataMember, Telerik.Windows.Data.FilterOperator.IsGreaterThanOrEqualTo, Nothing) 
        Me.compositeFilter.FilterDescriptors.Add(Me.fromFilter) 
 
        Me.toFilter = New Telerik.Windows.Data.FilterDescriptor(dataMember, Telerik.Windows.Data.FilterOperator.IsLessThanOrEqualTo, Nothing) 
        Me.compositeFilter.FilterDescriptors.Add(Me.toFilter) 
    End Sub 
 
    Private Sub OnFilter(ByVal sender As Object, ByVal e As RoutedEventArgs) 
        Me.fromFilter.Value = Me.FromDate 
        Me.toFilter.Value = Me.ToDate 
 
        If Not Me.column.DataControl.FilterDescriptors.Contains(Me.compositeFilter) Then 
            Me.column.DataControl.FilterDescriptors.Add(Me.compositeFilter) 
        End If 
 
        Me.IsActive = True 
    End Sub 
 
    Private Sub OnClear(ByVal sender As Object, ByVal e As RoutedEventArgs) 
        If Me.column.DataControl.FilterDescriptors.Contains(Me.compositeFilter) Then 
            Me.column.DataControl.FilterDescriptors.Remove(Me.compositeFilter) 
        End If 
 
        Me.FromDate = New Date(1990, 1, 1) 
        Me.ToDate = New Date(1995, 1, 1) 
 
        Me.IsActive = False 
    End Sub 
End Class 

Finally, you have to tell the column to use this custom filtering control like this:

<telerik:RadGridView Name="radGridView" AutoGenerateColumns="False"> 
  <telerik:RadGridView.Columns>      
    <telerik:GridViewDataColumn DataMemberBinding="{Binding Id}"/> 
    <telerik:GridViewDataColumn DataMemberBinding="{Binding ModifiedAt}"> 
      <telerik:GridViewDataColumn.FilteringControl> 
        <local:FromDateToDateFilterControl FromDate="1/1/1990" ToDate="1/1/1995"/> 
      </telerik:GridViewDataColumn.FilteringControl> 
    </telerik:GridViewDataColumn> 
  </telerik:RadGridView.Columns> 
</telerik:RadGridView> 

In case you are using NoXaml Binaries and Implicit Styles, please refer to the Styling custom controls section.

If you want to customize the default FilteringControl used by the GridView, you can edit its ControlTemplate as mentioned in the Styling FilteringControl and FilteringDropDown article.

See Also

In this article