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.

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
- Create a new Windows Forms App.
- To create separate panels for placing controls, drag and drop the MS SplitContainer from the Toolbox onto your form.
- 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.
- 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.
- 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
- 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
private void CreateDataSource()
{
OleDbConnection con = 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);
}
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
- 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
private void CreateDataSource()
{
OleDbConnection con = 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);
}
Back to Top
Step 3: Configuring FlexGrid control
- 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
//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,
10f, 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.
- 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)
//Add unbound columns to the FlexGrid
c1FlexGrid1.Cols.Add(_colCount);
//Retrieve data for the unbound cells
c1FlexGrid1.GetUnboundValue += _flex_GetUnboundValue;
Note that _colCount is defined as a global variable with value equal to 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
private void _flex_GetUnboundValue(object sender, UnboundValueEventArgs e)
{
//Fetch the cell style to get the UserData property value which returns
//the car Id.
CellStyle cs = c1FlexGrid1.Styles["CellStyle" + e.Row + "," + e.Col];
//Display car image and information in the cell depending on car Id
//fetched above
if (cs != null && cs.UserData != null)
{
int carId = Convert.ToInt32(cs.UserData) - 1;
c1FlexGrid1.SetCellImage(e.Row, e.Col,
GetImagesFromByteArray((Byte[])_carsTable.Rows[carId]["Picture"]));
e.Value = "Model: " + _carsTable.Rows[carId]["Model"] +
"\nBrand:" + _carsTable.Rows[carId]["Brand"] + "\nPrice:" +
_carsTable.Rows[carId]["Price"];
}
}
Note that the GetUnboundValue event handler uses the ‘GetImagesFromByteArray’ method to retrieve the car images stored as OLE objects in the Access database.
- 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
private Image GetImagesFromByteArray(byte[] picData)
{
//Generate car image using the image data saved as byte array
if (picData == null)
{
return null;
}
int bmData = (picData[0] == 0x15 && picData[1] == 0x1c) ? 78 : 0;
System.IO.MemoryStream ms = new System.IO.MemoryStream(picData,
bmData, picData.Length - bmData);
return Image.FromStream(ms);
}
Back to Top
Step 4: Configuring DataFilter control
- 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
//Automatically generates the filters
c1DataFilter1.AutoGenerateFilters = true;
- 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)
//Modify the automatically generated filters
c1DataFilter1.FilterAutoGenerating += C1DataFilter1_FilterAutoGenerating;
- 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
private void C1DataFilter1_FilterAutoGenerating(object sender,
C1.DataFilter.FilterAutoGeneratingEventArgs e)
{
//Modify the automatically generated filters
switch (e.Property.Name)
{
//Set the checklist items for Category filter
case "Category":
var categoryFilter = (C1.Win.DataFilter.ChecklistFilter)e.Filter;
categoryFilter.ItemsSource = _carsTable;
categoryFilter.ValueMemberPath = "Category";
categoryFilter.SelectAll();
break;
//Set the checklist items for Brand filter
case "Brand":
var brandFilter = (C1.Win.DataFilter.ChecklistFilter)e.Filter;
brandFilter.ItemsSource = _carsTable;
brandFilter.ValueMemberPath = "Brand";
brandFilter.SelectAll();
break;
//Set the minimum/maximum value for the Liter filter
case "Liter":
var literFilter = (C1.Win.DataFilter.RangeFilter)e.Filter;
literFilter.Maximum =
_carsTable.AsEnumerable().Max(x => x.Field<double>("Liter"));
literFilter.Minimum =
_carsTable.AsEnumerable().Min(x => x.Field<double>("Liter"));
literFilter.Increment = 0.01;
literFilter.Digits = 3;
break;
//Set the minimum/maximum value for the Price filter
case "Price":
var priceFilter = (C1.Win.DataFilter.RangeFilter)e.Filter;
priceFilter.Maximum =
_carsTable.AsEnumerable().Max(x => x.Field<double>("Price"));
priceFilter.Minimum =
_carsTable.AsEnumerable().Min(x => x.Field<double>("Price"));
priceFilter.Increment = 1000;
priceFilter.Digits = 0;
break;
default:
e.Cancel = true;
break;
}
}
- 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
//This event is fired when the filter changes hence it is used retrieve the
//relevant information regarding the filtered rows
c1DataFilter1.FilterChanged += C1DataFilter1_FilterChanged;
- 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
private void C1DataFilter1_FilterChanged(object sender, EventArgs e)
{
//Reconfigure FlexGrid
c1FlexGrid1.Styles.Clear();
c1FlexGrid1.Row = -1; // Clear default selection from FlexGrid
for (int col = 0; col < _colCount; col++)
{
c1FlexGrid1.Cols[col].ImageAlign = ImageAlignEnum.CenterTop;
c1FlexGrid1.Cols[col].TextAlign = TextAlignEnum.CenterBottom;
}
//Get the list of filtered rows
List<DataRowView> filteredCars = c1DataFilter1.View.Cast<DataRowView>().ToList();
//Save the car Id using the UserData property of CellStyle
for (int row = 0; row < filteredCars.Count; row++)
{
CellStyle cs = c1FlexGrid1.Styles.Add("CellStyle" +
row / _colCount + "," + row % _colCount);
cs.UserData = filteredCars[row].Row["ID"];
}
//Since the data from the filtered rows will be rendered in
//three columns, so hide the extra rows in FlexGrid
int rowCount = (int)Math.Ceiling(filteredCars.Count / (double)_colCount);
for (int i = rowCount; i < c1FlexGrid1.Rows.Count; i++)
c1FlexGrid1.Rows[i].Visible = false;
}
- In the Form_Load event, bind the DataFilter control to the same datasource which was assigned to the FlexGrid control.
c1DataFilter1.DataSource = _carsTable
c1DataFilter1.DataSource = _carsTable;
- 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.