Back to Devexpress

Filtering Events

windowsforms-114963-common-features-filtering-ui-context-filtering-events.md

latest15.5 KB
Original Source

Filtering Events

  • Sep 13, 2023
  • 9 minutes to read

Handling filtering events allows you to customize editors the Filtering UI Context generates and manage UI generation for complex (Sting, Object) properties.

The PrepareTemplate and CustomizeTemplate Events

These events allow you to alter ( CustomizeTemplate ) or completely replace ( PrepareTemplate ) templates that the Filtering UI Context component employs when generating editors. In the sample below, handling the PrepareTemplate replaces the default CheckedListBoxControl with a custom “TileList” control that displays filtering options as flat buttons.

csharp
filteringUIContext1.PrepareTemplate += filteringUIContext1_PrepareTemplate;

void filteringUIContext1_PrepareTemplate(object sender, FilteringUIPrepareTemplateEventArgs e) {
    if (e.PropertyPath == "CategoryID")
        e.Template = new TileList() { Images = categoryImages };
    if (e.PropertyPath == "Status")
        e.Template = new TileList() { Images = statusImages };
}
vb
Private filteringUIContext1.PrepareTemplate += AddressOf filteringUIContext1_PrepareTemplate

Private Sub filteringUIContext1_PrepareTemplate(ByVal sender As Object, ByVal e As FilteringUIPrepareTemplateEventArgs)
    If e.PropertyPath = "CategoryID" Then
        e.Template = New TileList() With {.Images = categoryImages}
    End If
    If e.PropertyPath = "Status" Then
        e.Template = New TileList() With {.Images = statusImages}
    End If
End Sub

The CustomizeTemplate allows you to customize a template without replacing it.

csharp
filteringUIContext1.CustomizeTemplate += FilteringUIContext1_CustomizeTemplate;

private void FilteringUIContext1_CustomizeTemplate(object sender, FilteringUICustomizeTemplateEventArgs e) {
    if (e.PropertyPath == "CategoryID" || e.PropertyPath == "Status") {
        TileList list = e.Template as TileList;
        list.Appearance.ForeColor = System.Drawing.Color.FromArgb(60, 60, 60);
    }
}
vb
Private filteringUIContext1.CustomizeTemplate += AddressOf FilteringUIContext1_CustomizeTemplate

Private Sub FilteringUIContext1_CustomizeTemplate(ByVal sender As Object, ByVal e As FilteringUICustomizeTemplateEventArgs)
    If e.PropertyPath = "CategoryID" OrElse e.PropertyPath = "Status" Then
        Dim list As TileList = TryCast(e.Template, TileList)
        list.Appearance.ForeColor = System.Drawing.Color.FromArgb(60, 60, 60)
    End If
End Sub

The QueryLookupData Event

Allows you to provide the child items list for lookup filters manually. This event handler’s QueryLookupDataEventArgs argument provides the following properties:

  • PropertyPath - the name of the data field for which the current lookup editor was created;
  • Result - exposes three properties for populating your lookup editor:

The code sample below illustrates the “RetrieveCategoryList” method, which iterates through Data Grid records and adds unique “Category_Name” column values to a list. This list is later used as an item source for the filtering lookup editor.

csharp
// Write category names in a list
public List<String> RetrieveCategoryList() {
    category_QueryTableAdapter1.Fill(vehiclesDataSet1.Category_Query);
    DataTable dt = vehiclesDataSet1.Tables["Category Query"];
    List<String> myList = new List<string>();
    foreach(DataRow row in dt.Rows) {
        string category = row["Category_Name"].ToString();
        if(!myList.Contains(category)) myList.Add(category);
    }
    return myList;
}

// Provide a list of child lookup items and limit the number of initially visible items
private void filteringUIContext1_QueryLookupData(object sender, DevExpress.Utils.Filtering.QueryLookupDataEventArgs e) {
    if(e.PropertyPath == "Category_Name") {
        e.Result.DataSource = this.RetrieveCategoryList();
        e.Result.Top = 7;
    }
}
vb
' write category names into a list
Public Function RetrieveCategoryList() As List(Of String)
    category_QueryTableAdapter1.Fill(vehiclesDataSet1.Category_Query)
    Dim dt As DataTable = vehiclesDataSet1.Tables("Category Query")
    Dim myList As New List(Of String)()
    For Each row As DataRow In dt.Rows
        Dim category As String = row("Category_Name").ToString()
        If Not myList.Contains(category) Then
          myList.Add(category)
        End If
    Next row
    Return myList
End Function

' provide a list of child lookup items and limit the number of initially visible items
Private Sub filteringUIContext1_QueryLookupData(ByVal sender As Object, ByVal e As DevExpress.Utils.Filtering.QueryLookupDataEventArgs)
    If e.PropertyPath = "Category_Name" Then
        e.Result.DataSource = Me.RetrieveCategoryList()
        e.Result.Top = 7
    End If
End Sub

QueryLookupData and other “Query…” events allow you to customize filtering items’ HTML texts. For instance, the following code sample from the Data Filtering Charts demo illustrates how to provide images to items under the “Company” category.

csharp
void filteringUIContext_QueryLookupData(object sender, DevExpress.Utils.Filtering.QueryLookupDataEventArgs e) {
    if (e.PropertyPath == "Company")
        e.WithDataItems(GetHtmlImages);
}

void GetHtmlImages(DataItemsExtension.DataItems dataItems) {
    foreach (ExcelFilterDataItem item in dataItems) {
        string companyName = (string)item.Value;
        item.HtmlText = "<image=" + companyName + "><nbsp>" + item.Text;
    }
    dataItems.HtmlImages = images;
}
vb
Private Sub filteringUIContext_QueryLookupData(ByVal sender As Object, ByVal e As DevExpress.Utils.Filtering.QueryLookupDataEventArgs)
    If e.PropertyPath = "Company" Then
        e.WithDataItems(AddressOf GetHtmlImages)
    End If
End Sub

Private Sub GetHtmlImages(ByVal dataItems As DataItemsExtension.DataItems)
    For Each item As ExcelFilterDataItem In dataItems
        Dim companyName As String = CStr(item.Value)
        item.HtmlText = "<image=" & companyName & "><nbsp>" & item.Text
    Next item
    dataItems.HtmlImages = images
End Sub

The QueryGroupData Event

If you want to group multiple data fields in one hierarchical drop-down filter, you need to decorate the root field with the FilterGroup attribute.

csharp
public class SpaceObject
{
    public int ID { get; set; }
    public int ParentID { get; set; }

    public string Name { get; set; }
    public string Notes { get; set; }
    public int MeanRadiusInKM { get; set; }
    public double MeanRadiusByEarth { get; set; }
    [DevExpress.Utils.Filtering.FilterGroup("ParentID;Name")]
    public string TypeOfObject { get; set; }
    public bool Mark { get; set; }
}
vb
Public Class SpaceObject
    Public Property ID() As Integer
    Public Property ParentID() As Integer

    Public Property Name() As String
    Public Property Notes() As String
    Public Property MeanRadiusInKM() As Integer
    Public Property MeanRadiusByEarth() As Double
    <DevExpress.Utils.Filtering.FilterGroup("ParentID;Name")>
    Public Property TypeOfObject() As String
    Public Property Mark() As Boolean
End Class

In case the Filtering UI Context component is attached to a data-aware control (the Client property), all you need to do is to decorate required fields with this attribute. Otherwise, if the Filtering UI Context recieves a filtering Model (the ModelType property), you need to use this attribute and handle the QueryGroupData. This event supplies grouped drop-down filters with data, and has the following parameters:

  • PropertyPath - returns a field name decorated with the FilterGroup attribute;
  • GroupPropertyPath - returns a field name that corresponds to the current group level;
  • Result.SetGroupData - allows you to set values and captions for fitler items;
  • ParentCriteria - returns criteria that can be used to obtain values for the current group level;
  • ParentValues - returns an array with parent nodes’ values.

In the sample above, the “TypeOfObject” field is decorated with the FilterGroup attribute. For this field the Filtering UI Context should display a drop-down list with the “ParentId” and “Name” field values as children. The code below illustrates how to provide these child values.

csharp
private void filteringUIContext1_QueryGroupData(object sender, DevExpress.Utils.Filtering.QueryGroupDataEventArgs e) {
    // column
    if (e.PropertyPath == "TypeOfObject") {
        object[] values = null;
        string[] displayValues = null;

        // level
        if (e.GroupPropertyPath == "ParentID") {
            string parentType = (string)e.ParentValues[0];
            var parentIDs = allObjects.Where(x => x.TypeOfObject == parentType)
                .Select(x => x.ParentID)
                .Distinct() // values should be unique
                .OrderBy(x => x);// and sorted

            values = allObjects.Where(x => x.TypeOfObject == parentType)
               .Select(x => x.ParentID)
               .Distinct() // values should be unique
               .OrderBy(x => x)// and sorted
            .Cast<object>()
            .ToArray();

            displayValues = parentIDs.Select(x => x.ToString()).ToArray();
        }
        else if (e.GroupPropertyPath == "Name") {
            // prepare values for the specific group level using ParentValues for filtering
            string parentType = (string)e.ParentValues[0];
            int parentID = (int)e.ParentValues[1];

            displayValues = allObjects.Where(x => x.TypeOfObject == parentType && x.ParentID == parentID)
                .Select(x => x.Name)
                .Distinct() // values should be unique
                .OrderBy(x => x) // and sorted
                .ToArray();
            values = displayValues;
        }
        else {
            // prepare root values
            displayValues = allObjects.Select(x => x.TypeOfObject)
                .Distinct() // values should be unique
                .OrderBy(x => x) // and sorted
                .ToArray();
            values = displayValues;
        }
        e.Result.SetGroupData(values, displayValues);
    }
}
vb
Private Sub filteringUIContext1_QueryGroupData(ByVal sender As Object, ByVal e As DevExpress.Utils.Filtering.QueryGroupDataEventArgs)
    ' column
    If e.PropertyPath = "TypeOfObject" Then
        Dim values() As Object = Nothing
        Dim displayValues() As String = Nothing

        ' level
        If e.GroupPropertyPath = "ParentID" Then
            Dim parentType As String = CStr(e.ParentValues(0))
            Dim parentIDs = allObjects.Where(Function(x) x.TypeOfObject = parentType).Select(Function(x) x.ParentID).Distinct().OrderBy(Function(x) x) ' and sorted - values should be unique

            values = allObjects.Where(Function(x) x.TypeOfObject = parentType).Select(Function(x) x.ParentID).Distinct().OrderBy(Function(x) x).Cast(Of Object)().ToArray() ' and sorted - values should be unique

            displayValues = parentIDs.Select(Function(x) x.ToString()).ToArray()
        ElseIf e.GroupPropertyPath = "Name" Then
            ' prepare values for the specific group level using ParentValues for filtering
            Dim parentType As String = CStr(e.ParentValues(0))
            Dim parentID As Integer = CInt(Math.Truncate(e.ParentValues(1)))

            displayValues = allObjects.Where(Function(x) x.TypeOfObject = parentType AndAlso x.ParentID = parentID).Select(Function(x) x.Name).Distinct().OrderBy(Function(x) x).ToArray() ' and sorted - values should be unique
            values = displayValues
        Else
            ' prepare root values
            displayValues = allObjects.Select(Function(x) x.TypeOfObject).Distinct().OrderBy(Function(x) x).ToArray() ' and sorted - values should be unique
            values = displayValues
        End If
        e.Result.SetGroupData(values, displayValues)
    End If
End Sub

The QueryRangeData Event

Handle this event to customize filtering editors for numeric properties. The QueryRangeDataEventArgs argument provides the following properties:

  • PropertyPath - the name of the data field for which the current lookup editor was created;
  • Result - provides access to the Minimum , Maximum and Average properties that allow you to limit the available value range.

In the following example, end-users can filter records by price only in $500 ~ $2000 range:

csharp
void filteringUIContext1_QueryRangeData(object sender, DevExpress.Utils.Filtering.QueryRangeDataEventArgs e) {
    if(e.PropertyPath == "Price") {
        e.Result.Minimum = 500;
        e.Result.Maximum = 2000;
    }
}
vb
Private Sub filteringUIContext1_QueryRangeData(ByVal sender As Object, ByVal e As DevExpress.Utils.Filtering.QueryRangeDataEventArgs)
    If e.PropertyPath = "Price" Then 
        e.Result.Minimum = 500
        e.Result.Maximum = 2000
    End If 
End Sub

The QueryBooleanChoiceData Event

Handle this event to ignore unwanted boolean filtering values (see the example below). The event receives an argument of the QueryBooleanChoiceDataEventArgs type, which provides access to the following properties:

  • PropertyPath - the name of the data field for which the current lookup editor was created;
  • Result.DefaultValue - assign an unwanted boolean value to this property. If a user selects this unwanted value, no filter applies (see the example below).

In the example below, Data Grid is bound to a source that provides the “In Stock” field. It is unlikely that customers would like to browse only unavailable products, so for this property the false value is irrelevant.

csharp
private void filteringUIContext1_QueryBooleanChoiceData(object sender, DevExpress.Utils.Filtering.QueryBooleanChoiceDataEventArgs e) {
    if(e.PropertyPath == "InStock") {
        e.Result.DefaultValue = false;
    }
}
vb
Private Sub filteringUIContext1_QueryBooleanChoiceData(ByVal sender As Object, ByVal e As DevExpress.Utils.Filtering.QueryBooleanChoiceDataEventArgs)
    If e.PropertyPath = "InStock" Then 
        e.Result.DefaultValue = False 
    End If 
End Sub

The animation below illustrates the result: when a user clears the “In Stock” checkbox, the Data Grid displays all records instead of showing only those whose “In Stock” values equal false.

See Also

Filtering Attributes