FlexGrid for WPF | ComponentOne
Features / Data Filtering / Filter Data using IDataCollection
In This Topic
    Filter Data using IDataCollection
    In This Topic

    The IDataCollection interface supports data filtering in FlexGrid through the Filter property. The Filter property  specifies a method to call for each item in the collection. If the method returns true, the item is included in the view. If the method returns false, the item is filtered out of view. (This type of method is called a predicate). In the following section learn how to implement Filter Data using DataCollection in FlexGrid .NET and .NET Framework versions.

     

    Let us take a user control named SearchBox that consists of a TextBox control where the user types a value to search, and a timer that provides a small delay to allow users to type the values to search for without re-applying the filter after each character. Here we use DataCollection filter to implement Search box.

    When the user stops typing, the timer elapses and applies the filter using this code:

    C#
    Copy Code
    _view.Filter = null;
    _view.Filter = (object item) =>
    {
        // get search text
        var srch = _txtSearch.Text;
    
        // no text? show all items
        if (string.IsNullOrEmpty(srch))
            {
                return true;
            }
    
    // show items that contain the text in any of the specified properties
        foreach (PropertyInfo pi in _propertyInfo)
        {
           var value = pi.GetValue(item, null) as string;
           if (value != null && value.IndexOf(srch, StringComparison.OrdinalIgnoreCase) > -1)
              {
                 return true;
              }
        }
    
      // exclude this item...
      return false;
    };
    

    Note how the code sets the value of the Filter property using a lambda function. We could have provided a separate method, but this notation is often more convenient because it is concise and allows us to use local variables if we need them.

    The lambda function takes an item as a parameter, gets the value of the specified properties for the object, and returns true if any of the object's properties contain the string being searched for.

    For example, if the objects are of type "Song" and the properties specified are "Title," "Album," and "Artist," then the function returns true if the string being searched for is found in the song's title, album, or artist. This is a powerful and easy-to-use search mechanism similar to the one used in Apple's iTunes application.

    As soon as the filter is applied, the grid (and any other controls bound to the DataCollection object) reflect the result of the filter by showing only the items selected by the filter.

    Note that filtering and grouping work together. The image below (from the MainTestApplication sample) shows a very large song list with a filter applied to it:

    Filtering

    The image shows the filter set to the word “Water.” The filter looks for matches in all fields (song, album, artist), so all “Creedence Clearwater Revival” songs are automatically included.

    Notice the status label above the grid. It automatically updates whenever the list changes, so when the filter is applied the status updates to reflect the new filter. The routine that updates the status uses LINQ to calculate the number of artists, albums, and songs selected, as well as the total storage and play time. The song status update routine is implemented as follows:

    C#
    Copy Code
    // update song status
     void UpdateSongStatus()
     {
       var view = _flexiTunes.ItemsSource as DataCollection;
       var songs = view.OfType<Song>();
       _txtSongs.Text = string.Format(
          "{0:n0} Artists; {1:n0} Albums; {2:n0} Songs; " +
          "{3:n0} MB of storage; {4:n2} days of music.",
         (from s in songs select s.Artist).Distinct().Count(),
         (from s in songs select s.Album).Distinct().Count(),
         (from s in songs select s.Name).Count(),
         (double)(from s in songs select s.Size/1024.0/1024.0).Sum(),
         (double)(from s in songs select s.Duration/3600000.0/24.0).Sum());
     }
    

    This routine is not directly related to the grid, but is listed here because it shows how you can leverage the power of LINQ to summarize status information that is often necessary when showing grids bound to large data sources.

    The LINQ statement above uses the Distinct and Count commands to calculate the number of artists, albums, and songs currently exposed by the data source. It also uses the Sum command to calculate the total storage and play time for the current selection.

    The Filter predicate of DataCollection cannot filter the child rows. To filter a child row, the type of child rows must be DataCollection. You can filter both child rows and parent grid. However, you need to make sure that the parent and child both must be of DataCollection type and their binding names should also be different. Note that filtering child rows using DataCollection does not support sorting as of now.

    Let us take a user control named SearchBox that consists of a TextBox control where the user types a value to search, and a timer that provides a small delay to allow users to type the values to search for without re-applying the filter after each character. Here we use DataCollection filter to implement Search box.

    When the user stops typing, the timer elapses and applies the filter using this code:

    Note how the code sets the value of the Filter property using a lambda function. We could have provided a separate method, but this notation is often more convenient because it is concise and allows us to use local variables if we need them.

    The lambda function takes an item as a parameter, gets the value of the specified properties for the object, and returns true if any of the object's properties contain the string being searched for.

    C#
    Copy Code
    C1DataCollection<Customer> _view;
    public MainWindow()
    {
        InitializeComponent();
    
        //Generate grid data
        var customerlist = Customer.GetCustomerList(50);
        _view = new C1.DataCollection.C1DataCollection<Customer>(customerlist);
        //Binding the grid with data             
        grid.ItemsSource = _view;            
    }
    
    private void filter_Click(object sender, RoutedEventArgs e)
    {
        //get search text
        if (!string.IsNullOrEmpty(_txtSearch.Text))
        {                
            FilterTextExpression filterText = new FilterTextExpression("FirstName", FilterOperation.Equal, _txtSearch.Text, false, false);
            _view.FilterAsync(filterText);
        }
    

    To apply multi-value filtering

    FlexGrid allows you to apply multi-value filtering to columns which can be used to filter out relevant information by selecting multiple values at the same time. The multi-value filter provides the dropdown list of all values with checkboxes that let the user select the values which are to be displayed in the output. You can then simply select values from that list to apply filtering on different types of data to narrow down the display records.

    Let's say, you want to expand your business in certain countries, and, you need to contact your customers from those specific countries only. For this, you need to get the list of customers belonging to those countries which can be easily achieved by applying multi-value filtering to the Country column. The following example shows how you can achieve this.

    The following gif shows how you can perform multi-value filtering to select multiple countries at runtime.

    Displays multi-value filtering

    You can apply multi-value filtering in FlexGrid by simply adding the FlexGridFilter control to your application which provides value and condition filters. Alternatively, you can use the FilterType property of the ColumnFilter class to set the filter type to Value.

    Use the following code snippet to enable multi-value filtering for the Country column.

    //Approach 1: enable filtering through FlexGridFilter
    var gridFilter = new C1FlexGridFilter(grid);
            
    //Approach 2: specify filter type for country column
    var columnFilter = gridFilter.GetColumnFilter(flex.Columns["Country"]);
    columnFilter.FilterType = FilterType.Value;
    

    To apply multi-value filtering, create an instance of the ChecklistFilter class and add it to the FilterCollection of the DataFilter class using the Add() method. Furthermore, you can add filter items using the ItemSource property of the ChecklistFilter class. Also, you can set the name of the data field for which the filter is being defined by using the PropertyName property of the Filter class.

    The following code uses the Customer class created in Quick Start. Here, the FlexGrid columns are bound to the customer's first name, last name, order total, order count, country id, last order date, and last order time as shown in the following XAML code.

    <c1:FlexGrid x:Name="grid" AutoGenerateColumns="False">
        <c1:FlexGrid.Columns>
            <c1:GridColumn Binding="FirstName"/>
            <c1:GridColumn Binding="LastName"/>
            <c1:GridColumn Binding="OrderTotal" Format="C2"/>
            <c1:GridColumn Binding="OrderCount" Format="N1"/>
            <c1:GridColumn Binding="CountryId" Header="Country Id" FilterLoading="Country_FilterLoading"/>
            <c1:GridDateTimeColumn Binding="LastOrderDate" Mode="Date"/>
            <c1:GridDateTimeColumn Binding="LastOrderDate" Header="Last Order Time" Mode="Time"/>
        </c1:FlexGrid.Columns>
    </c1:FlexGrid>
                                            
    

    To apply multi-value filtering on the Country column in the grid created above, create an instance of ChecklistFilter class and add list items to it using the ItemsSource property as shown in the following code.

    private void Country_FilterLoading(object sender, C1.WPF.Grid.GridColumnFilterLoadingEventArgs e)
        {
            e.DataFilter.Filters.Clear();
            C1.WPF.DataFilter.ChecklistFilter filter = new C1.WPF.DataFilter.ChecklistFilter();
            List<object> filterList = new List<object>();
                    foreach (Customer data in grid.ItemsSource)
                filterList.Add(data.Country);
                filter.ItemsSource = filterList;
                filter.PropertyName = "Country";
                e.DataFilter.Filters.Add(filter);
        }
    
    See Also