Walkthrough / Using DataFilter with FlexGrid
Using DataFilter with FlexGrid

FlexGrid provides built-in filtering support with the help of column filters. However, consider a scenario where you want a filtering UI similar to the one seen in different e-commerce websites where a grid displaying the product listing shows only few attributes such as the product image, product name and product price. Although, the user is allowed to filter the product listing by many other attributes such as brand, category, price etc. It is not possible to set such kind of filters from column filters in data grid controls. Hence, this walkthrough explains how you can use the DataFilter control to filter FlexGrid content using a filtering UI similar to any online store’s website.

The following image shows a list of cars filtered by a specific brand, category and price in FlexGrid using the DataFilter control.

DataFilter with FlexGrid

To create an application for filtering a car list by brand, category, and price, complete the following steps:

Step 1: Setting up the application UI

  1. Create a new Windows Forms App.
  2. To create separate panels for placing controls, drag and drop the MS SplitContainer from the Toolbox onto your form.
  3. To add an icon or a logo representing a company or business, drag and drop the MS PictureBox control from the Toolbox onto Panel1 of the SplitContainer control. Set its Dock property to Top and add an image to the control using its Image property.
  4. To show different filtering criterias such as brand, category, etc., drag and drop the DataFilter control from the Toolbox onto Panel1 of the SplitContainer control. Set its Dock property to Bottom.
  5. To display a list of cars, drag and drop the FlexGrid control from the Toolbox onto Panel2 of the SplitContainer control. Set its Dock property to Fill.

Back to Top

Step 2: Creating data source for FlexGrid and DataFilter

  1. Define a method, for example CreateDataSource, to create datasource for the FlexGrid and DataFilter controls.
    Private Sub CreateDataSource()
            Dim con As OleDbConnection = New OleDbConnection(("provider=microsoft.jet.oledb.4.0;Data Source="  _
            + (Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\ComponentOne Samples\Common\C1NWind.mdb")))
            _carsTable = New DataTable
            (New OleDbDataAdapter("Select * from Cars", con) + Fill(_carsTable))
    End Sub
    

    Note that _carsTable is declared as a global variable of type DataTable.

    Note: DataBinding is also possible in the DataFilter control using the DataEngine library. Please refer the DataFilterAndDataEngine sample in \Documents\ComponentOne Samples\WinForms\v4.5.2\DataFilter\CS
  2. Invoke the method from the Form’s Load event handler to generate the data for FlexGrid and DataFilter controls.
    Private Sub CreateDataSource()
            Dim con As OleDbConnection = New OleDbConnection(("provider=microsoft.jet.oledb.4.0;Data Source="  _
            + (Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\ComponentOne Samples\Common\C1NWind.mdb")))
            _carsTable = New DataTable
            (New OleDbDataAdapter("Select * from Cars", con) + Fill(_carsTable))
    End Sub
    

Back to Top

Step 3: Configuring FlexGrid control

  1. To bind the FlexGrid control to a data source and set its properties, add the following code to the Form Load event handler.
    'Configure FlexGrid
    c1FlexGrid1.AutoGenerateColumns = false
    c1FlexGrid1.DataSource = _carsTable
    'Hide the topmost row displaying the column names
    c1FlexGrid1.Rows.Fixed = 0
    'Remove the columns added by by default
    c1FlexGrid1.Cols.Count = 0
    'Setting additional properties of the grid
    c1FlexGrid1.Styles.Normal.Font = New Font(FontFamily.GenericSansSerif, 10!, FontStyle.Regular)
    c1FlexGrid1.Rows.DefaultSize = 208
    c1FlexGrid1.Cols.DefaultSize = 263
    

    Note that in order to filter the data-aware control, FlexGrid, using the DataFilter control, both the controls must share a common data source.

  2. To display the car image and information in a cell, add unbound columns to the FlexGrid control, for example, we have added three unbound columns to the FlexGrid control and subscribed the GetUnboundValue event to populate these columns with data.
    'Add unbound columns to the FlexGrid 
    c1FlexGrid1.Cols.Add(_colCount)
    'Retrieve data for the unbound cells
    c1FlexGrid1.GetUnboundValue = (c1FlexGrid1.GetUnboundValue + _flex_GetUnboundValue)
    

    Note that _colCount is defined as a global variable with value equal to 3.

  3. To populate the unbound columns with car data along with the images, add the following code to the GetUnboundValue event handler.
    Private Sub _flex_GetUnboundValue(ByVal sender As Object, ByVal e As UnboundValueEventArgs)
    'Fetch the cell style to get the UserData property value which returns
    'the car Id.
            Dim cs As CellStyle = c1FlexGrid1.Styles(("CellStyle"  _
            + (e.Row + ("," + e.Col))))
    'Display car image and information in the cell depending on car Id
    'fetched above
            If ((Not (cs) Is Nothing)  _
            AndAlso (Not (cs.UserData) Is Nothing)) Then
            Dim carId As Integer = (Convert.ToInt32(cs.UserData) - 1)
            c1FlexGrid1.SetCellImage(e.Row, e.Col, GetImagesFromByteArray(CType(_carsTable.Rows(carId)("Picture"),Byte())))
            e.Value = ("Model: "  _
            + (_carsTable.Rows(carId)("Model") + (""& vbLf&"Brand:"  _
            + (_carsTable.Rows(carId)("Brand") + (""& vbLf&"Price:" + _carsTable.Rows(carId)("Price"))))))
    End If
    End Sub
    

    Note that the GetUnboundValue event handler uses the ‘GetImagesFromByteArray’ method to retrieve the car images stored as OLE objects in the Access database.

  4. Define the GetImagesFromByteArray’ method using the following code.
    Private Function GetImagesFromByteArray(ByVal picData() As Byte) As Image
    'Generate car image using the image data saved as byte array
            If (picData Is Nothing) Then
                    Return Nothing
            End If
            
            Dim bmData As Integer = 78
    'TODO: Warning!!!, inline IF is not supported ?
            ((picData(0) = 21)  _
            AndAlso (picData(1) = 28))
            0
            Dim ms As System.IO.MemoryStream = New System.IO.MemoryStream(picData, bmData, (picData.Length - bmData))
            Return Image.FromStream(ms)
    End Function
    

Back to Top

Step 4: Configuring DataFilter control

  1. To automatically generate the filters, set the AutoGenerateFilters property of DataFilter to true in the Form Load event handler.
    'Automatically generates the filters
    c1DataFilter1.AutoGenerateFilters = true
    

  2. To define the filtering criterias such as the minimum /maximum values for the RangeFilter and the checklist items for the CheckListFilter, subscribe to the FilterAutoGenerating event in the Form_Load event.
    'Modify the automatically generated filters
    c1DataFilter1.FilterAutoGenerating = (c1DataFilter1.FilterAutoGenerating + C1DataFilter1_FilterAutoGenerating)
    

  3. Add the following code to the FilterAutoGenerating event handler to customize the automatically generated filters.
    Private Sub C1DataFilter1_FilterAutoGenerating(ByVal sender As Object, ByVal e As C1.DataFilter.FilterAutoGeneratingEventArgs)
      'Modify the automatically generated filters
            Select Case e.[Property].Name
            'Set the checklist items for Category filter
            Case "Category"
                Dim categoryFilter = CType(e.Filter, C1.Win.DataFilter.ChecklistFilter)
                categoryFilter.ItemsSource = _carsTable
                categoryFilter.ValueMemberPath = "Category"
                categoryFilter.SelectAll()
            'Set the checklist items for Brand filter
            Case "Brand"
                Dim brandFilter = CType(e.Filter, C1.Win.DataFilter.ChecklistFilter)
                brandFilter.ItemsSource = _carsTable
                brandFilter.ValueMemberPath = "Brand"
                brandFilter.SelectAll()
            'Set the minimum/maximum value for the Liter filter
            Case "Liter"
                Dim literFilter = CType(e.Filter, C1.Win.DataFilter.RangeFilter)
                literFilter.Maximum = _carsTable.AsEnumerable().Max(Function(x) x.Field(Of Double)("Liter"))
                literFilter.Minimum = _carsTable.AsEnumerable().Min(Function(x) x.Field(Of Double)("Liter"))
                literFilter.Increment = 0.01
                literFilter.Digits = 3
            'Set the minimum/maximum value for the Price filter
            Case "Price"
                Dim priceFilter = CType(e.Filter, C1.Win.DataFilter.RangeFilter)
                priceFilter.Maximum = _carsTable.AsEnumerable().Max(Function(x) x.Field(Of Double)("Price"))
                priceFilter.Minimum = _carsTable.AsEnumerable().Min(Function(x) x.Field(Of Double)("Price"))
                priceFilter.Increment = 1000
                priceFilter.Digits = 0
            Case Else
                e.Cancel = True
        End Select
    End Sub
    

  4. To handle the FilterChanged event and reset the FlexGrid to display the car information appropriately, subscribe to the FilterChanged event.
    Note that on applying the filter to the FlexGrid, the grid is rendered with the default settings. So, the FilterChanged event needs to be handled.
    'This event is fired when the filter changes hence it is used retrieve the
    'relevant information regarding the filtered rows
    c1DataFilter1.FilterChanged += C1DataFilter1_FilterChanged
    

  5. Add the following code to the FilterChanged event handler to reset FlexGrid to display the car information.
    Private Sub C1DataFilter1_FilterChanged(ByVal sender As Object, ByVal e As EventArgs)
            'Reconfigure FlexGrid
            c1FlexGrid1.Styles.Clear
            c1FlexGrid1.Row = -1
            ' Clear default selection from FlexGrid
            Dim col As Integer = 0
            Do While (col < _colCount)
                c1FlexGrid1.Cols(col).ImageAlign = ImageAlignEnum.CenterTop
                c1FlexGrid1.Cols(col).TextAlign = TextAlignEnum.CenterBottom
                col = (col + 1)
            Loop
            
            'Get the list of filtered rows            
            Dim filteredCars As List(Of DataRowView) = c1DataFilter1.View.Cast(Of DataRowView).ToList
            'Save the car Id using the UserData property of CellStyle
            Dim row As Integer = 0
            Do While (row < filteredCars.Count)
                Dim cs As CellStyle = c1FlexGrid1.Styles.Add(("CellStyle"  _
                                + ((row / _colCount) + (","  _
                                + (row Mod _colCount)))))
                cs.UserData = filteredCars(row).Row("ID")
                row = (row + 1)
            Loop
            'Since the data from the filtered rows will be rendered in
            'three columns, so hide the extra rows in FlexGrid
            Dim rowCount As Integer = CType(Math.Ceiling((filteredCars.Count / CType(_colCount,Double))),Integer)
            Dim i As Integer = rowCount
            Do While (i < c1FlexGrid1.Rows.Count)
                c1FlexGrid1.Rows(i).Visible = false
                i = (i + 1)
            Loop
    End Sub
    

  6. In the Form_Load event, bind the DataFilter control to the same datasource which was assigned to the FlexGrid control.
    c1DataFilter1.DataSource = _carsTable
    

  7. Run the application and observe how the cars data with image appear in the FlexGrid control while all the car attribute filters are added to the DataFilter control.
    Now, you can change the filter values in the DataFilter UI and see how the FlexGrid renders the filtered data.

Back to Top

Note: The above mentioned sample codes are only supported in WinForms .NET Framework.