Skip to main content Skip to footer

How to Create a Custom Data Filter for a WinForms Datagrid

FlexGrid provides built-in filtering support through the use of column filters. However, there may be a scenario where you would prefer to apply your own custom filtering instead. The ability to apply custom filters to your FlexGrid is a powerful tool that can provide deep insights into your data analysis.

The functionality is already built into the FlexGrid control’s library using the IC1ColumnFilter and IC1ColumnFilterEditor interfaces. In this blog, we’ll learn how to apply a custom filter such as "Last Fiscal Year" to a FlexGrid DateTime column in a .NET 6 application.

Let’s get started!

Ready to Start Creating? Download ComponentOne Today

Set up the Project

First, open Visual Studio and make a new .NET 6 WinForms application. We will be naming ours “FlexGridCustomFilters”; you’ll find a download link to our project at the end of this blog.

Next, we download the C1.Win.FlexGrid 6.0 .dll file to our project via the NuGet Package Manager. With that successfully installed, we can now drag and drop a FlexGrid onto our form. We add some dummy shipping data to a DataTable object that we then bind to our FlexGrid. The dummy shipping data goes back 800 days, day by day, allowing us to test out some custom date filtering. Please view the sample attached for more information on the dummy data generation.

Create a Custom Filter

Now that we have a FlexGrid with data filled in it, let’s begin creating a custom filter for the “Shipping Date” column. For reference, the “Shipping Date” column contains DateTime values that go back 800 days, or over two years, into the past. For the sake of this sample, let’s say we have been instructed to create a custom filter that will reload the grid to display only orders shipped “Last Week”, “This Fiscal Year”, or “Last Fiscal Year” when the appropriate checkbox is selected during filter selection at runtime, similar to the screenshot below:

WinForms Datagrid Filter

To create a custom filter, you need to create a filter class that implements the IC1ColumnFilter interface, and an editor class that implements the IC1ColumnFilterEditor interface. The editor allows users to modify and configure the filter at runtime.

Create a Filter Class with IC1ColumnFilter

Let’s start with the filter class that implements the IC1ColumnFilter interface first. We’ll create a new file in our project called DateFilter.cs and implement the IC1ColumnFilter interface by writing the following during our class declaration:

class DateFilter : C1.Win.FlexGrid.IC1ColumnFilter

Next, we create some fields to keep track of DateFilter values at runtime:

DateTime _min = DateTime.MinValue;
DateTime _max = DateTime.MaxValue;

Then, we add in the object model’s getter and setter methods for the minimum and maximum values of our filter:

/// <summary>
/// Gets or sets the minimum date required by the filter.
/// </summary>
public DateTime Minimum
{
  get { return _min; }
  set { _min = value; }
}
/// <summary>
/// Gets or sets the maximum date required by the filter.
/// </summary>
public DateTime Maximum
{
  get { return _max; }
  set { _max = value; }
}

Lastly, we must include the required members implemented by the IC1ColumnFilter, which are the IsActive property, and the  Reset(), Apply(), and GetEditor() methods, as shown below:

#region ** IC1ColumnFilter Members

// filter is active if range doesn't cover all represetable dates.
public bool IsActive
{
  get { return _min != DateTime.MinValue || _max != DateTime.MaxValue; }
}

// reset filter.
public void Reset()
{
  _min = DateTime.MinValue;
  _max = DateTime.MaxValue;
}

// apply filter to a given date
public bool Apply(object value)
{
  var dt = (DateTime)value;
  return dt >= _min && dt <= _max;
}

// return editor control for this filter
IC1ColumnFilterEditor IC1ColumnFilter.GetEditor()
{
  return new DateFilterEditor();
}

#endregion 

Create a Filter Editor with IC1ColumnFilterEditor

Next, we must add a new user control to our project, which will include our editor class that implements the IC1ColumnFilterEditor Interface. We will be naming this user control DateFilterEditor.cs and defining the public partial class as follows:

public partial class DateFilterEditor : 
    UserControl,
    C1.Win.FlexGrid.IC1ColumnFilterEditor

First, we should go into the designer view of the user control to add in some standard checkboxes, which we will utilize within our custom filter methods that will be contained within our DateFilterEditor class.

Since we want to see the results for “Last Week”, “This Fiscal Year”, and “Last Fiscal Year”, we should drag three checkboxes onto the user control and name them accordingly. We can set the logic behind what happens when these checkboxes are checked later in this guide.

Similar to the DateFilter class we made earlier, we have a region for fields and constructors:

#region ** fields

DateFilter _filter;

#endregion

//-------------------------------------------------------------------------------
#region ** ctor

public DateFilterEditor()
{
  InitializeComponent();
}

#endregion

Similar to our DateFilter class that implemented IC1ColumnFilter, for our DaterFilterEditor class, we need to implement IC1ColumnFilterEditor to allow our DateFilterEditor objects to inherit the type IC1ColumnFilterEditor through polymorphism via implementation of the interface.

When implementing the IC1ColumnFilterEditor interface, we have to create a KeepFormOpen property, as well as an Initialize() and ApplyChanges() method. The ApplyChanges() method is where we will apply the logic to our custom filter selections. The following will complete our setup of the custom filter:

#region ** IC1ColumnFilterEditor

        public void Initialize(C1.Win.FlexGrid.C1FlexGridBase grid, int columnIndex, C1.Win.FlexGrid.IC1ColumnFilter filter)
        {
            _filter = (DateFilter)filter;
        }

        public void ApplyChanges()
        {
            // Begin ApplyChanges() method by resetting the filter states when a new filter is applied.
            _filter.Reset();

                // Set filter rules for last week filter
                if (_chkLastWeek.Checked)
                {
                    _filter.Maximum = DateTime.Today.AddDays(-7);
                    // This while loop will EXCLUDE Saturday from the result
                    while (_filter.Maximum.DayOfWeek != DayOfWeek.Saturday)
                    {
                        _filter.Maximum = _filter.Maximum.AddDays(1);
                    }
                    _filter.Minimum = DateTime.Today.AddDays(-7);
                    // This while loop will INCLUDE Monday from the result.
                    while (_filter.Minimum.DayOfWeek != DayOfWeek.Monday)
                    {
                        _filter.Minimum = _filter.Minimum.AddDays(-1);
                    }
                }

                // Set filter rules for last Fiscal Year. In this case, we want to say that the Fiscal Year starts April 1st and ends March 31st.
                if (_chkLastFiscalYear.Checked)
                {
                    _filter.Maximum = DateTime.Today.AddYears(-1);
                    _filter.Minimum = DateTime.Today.AddYears(-1);

                    // Set maximum filter to end at March 31st of current year.
                    while (_filter.Maximum.Month != 4 || _filter.Maximum.Day != 1)
                    {
                        _filter.Maximum = _filter.Maximum.AddDays(1);
                    }

                    // Set minimum filter to start at April 1st of last year.
                    while (_filter.Minimum.Month != 4 || _filter.Minimum.Day != 1)
                    {
                        _filter.Minimum = _filter.Minimum.AddDays(-1);
                    }
                }

                // Set the filter rules for this Fiscal Year. In this case, we want to say everything from the most recent April 1st up the present. Thus, we need two internal if statements to determine if April has already passed for this year.
                if(_chkThisFiscalYear.Checked)
                {
                    // Set the maximum to the current day + 1, since Maximum Bound for the filter is exclusive.
                    _filter.Maximum = DateTime.Today.AddDays(1);
                    // If today's month is January through March, then subtract a year from the minimum. For example, if today is January 2023, that means Fiscal Year started April 2022, so we have to use the AddYears(-1).Year when setting the DateTime for the minimum filter value.
                    if(DateTime.Today.Month < 4)
                    {
                        _filter.Minimum = new DateTime(DateTime.Today.AddYears(-1).Year, 4, 1);
                    }
                    // If today's month is April through December, then use the current year for "This Fiscal Year" starting point (minimum filter value) by simply using DateTime.Today.Year to set the year, as shown below.
                    if(DateTime.Today.Month >= 4)
                    {
                        _filter.Minimum = new DateTime(DateTime.Today.Year, 4, 1);
                    }
                }
            }
        }
        public bool KeepFormOpen
        {
            get { return false; }
        }

#endregion

Apply the Filter

To apply the filter to our FlexGrid, we must go back to our Form1.cs and set the filter for the “Ship Date” column to a new DateFilter object by calling the following line of code:

c1FlexGrid1.Cols["Ship Date"].Filter = new DateFilter();

Now, we can run our application, and when we open the column filter editor for the “Ship Date” column, we’ll see the checkbox options from our DateFilterEditor user control class:

WinForms Datagrid Filter

When we select the checkbox for one of our filters, it will apply the logic for the equivalent from inside our DateFilterEditor class’s ApplyChanges() method.

For example, if the “Last Week” checkbox is selected, the if(_chkLastWeek.Checked) block from within the ApplyChanges() method (inside our DateFilterEditor.cs class) will apply the proper filter logic on the displayed grid:

WinForms Datagrid Filter

To summarize what we accomplished in this blog, all this custom filter logic works through object polymorphism. By implementing IC1ColumnFilter and IC1ColumnFilterEditor interfaces, our custom DateFilter and DateFilterEditor classes inherit the types IC1ColumnFilter and IC1ColumnFilterEditor, respectively.

The FlexGrid column filters allow themselves to be set to objects of type IC1ColumnFilter, which our DateFilter objects are as well, all thanks to the principle of polymorphism applied through interface implementation.

Download the full sample.

Ready to Start Creating? Download ComponentOne Today!

comments powered by Disqus