Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

i00 BindingList with DataGridView

4.95/5 (21 votes)
22 Jul 2012Ms-PL4 min read 74.6K  
Simple to use BindingList and DataGridView that supports advanced LINQ filtering!
Image 1Please let me know if you use this in your projects by posting below.
A simple "I am using this in my project" will suffice.

Introduction

This project was designed to provide a simple way to add data to a list that could be filtered and sorted, with ease... but (as with most of my projects) this quickly grew to support lots of other features such as full LINQ filtering, a datagrid view that supports UIEditors, filtering plugins, a BindingNavigator that has filtering options and more!

Image 2

Features

BindingListView

  • Allows easy filtering
  • Allows easy sorting
  • Supports LINQ filtering

DataGridView

  • UI Type Editor drawing on cells
  • UI Type Editor support for cell editing
  • Inbuilt column header menus for sorting and filtering options
  • Data filtering plugins
  • Highlighting of filtered text
  • Faster than the standard DGV
  • Images scale to fit cells
  • Images can be selected by double clicking on an image cell
  • Lists and allows Enum options to be selected with ease

BindingNavigatorWithFilter

  • Adds filtering fields to the standard BindingNavigator

Implementation

To implement i00 BindingList into your project, first either:

  • Add the i00BindingList project to your solution and reference it (recommended)
  • Reference the i00BindingList.exe file that is output from this project
  • or you can bring all of *.vb files in the "i00BindingList" folder (from the zip) directly into your own project

Creating a Binding List

The Binding List can be created and filled just like any List(Of T):

VB.NET
'Create a i00BindingList.BindingListView of the required object... in this case "Person"
Dim blPersons As New i00BindingList.BindingListView(Of Person)
'... and to fill it:
Dim Person as New Person()
'fill person details here
blPersons.Add(Person)

Filtering a Binding List

The Binding List can be filtered by taking advantage of i00BindingList.BindingListView.Filter property. The i00BindingList filters are in LINQ and support calls to functions from within your project itself. For example the following will filter our list to show all of the people born in 1982:

VB.NET
blPersons.Filter = "(Year([DOB]) = 1982)"

To access a Public Shared Function (in this case PeopleFunctions.IsInFootballTeam()) in your project you can do so by going:

VB.NET
blPersons.Filter = GetType(PeopleFunctions).FullName & ".IsInFootballTeam([Me]) = True"

Note: that while using filtering [Me] and [Fields] must be in square brackets.

When filtering the Binding List the FilterChanged event is called.

Binding List Binding

The Binding List exposes a BindingSource Property that can be used as a DataSource for DataGridViews, or as a BindingSource for BindingNavigator.

The DataGridView

The i00BindingList.DataGridView inherits from DataGridView and can be used on custom data sources to allow support for UIEditors. UIEditors are part of the Net Framework and allow custom editors for items in the i00 DataGridView automatically as long as the AllowUIEditorCells and DrawUIEditorCells properties of the grid are set to true.

In the following you can see the ColorEditor in action:

Image 3

For more info on creating your own UIEditor's check this article.

Filtering Plugins for the the DataGridView

If a i00BindingList.DataGridView is bound to a i00BindingList.BindingListView it will automatically allow filtering from the header based on each column's data type. These can be extended to provided advanced filtering via plugins (as pictured below)

Image 4

Filter plugins are classes that implement i00BindingList.Plugins.iFilterPlugin; they automatically get picked up and allow the addition of extra filters based on each fields data type. Projects require no reference to the plugins (if they are in external files), however you will need to place them in the applications path.

The download project includes three filters ColorFilter (in the i00BindingList project), DateFilter and RecentDateTimeFilter (in the Test project).

Below is a list of implements and what they are used for after implementing iFilterPlugin:

  • Public ReadOnly Property DataTypes() As System.Type() - This should be set to return the data types (in an array) that we will be using this filter on.
  • Public ReadOnly Property Dispaly() As i00BindingList.Plugins.DisplayMethods - Sets when this filter will be displayed, options are DefaultHide, Always, DefaultShow
  • Public Sub LoadFromFilter(ByVal Filter As i00BindingList.AdvancedBindingSource.BasicFilterBase) - This is called when existing filter data (BasicFilterBase) is loaded and should update the controls in MenuItems accordingly.
  • Public Function MenuItems() As System.Collections.Generic.List(Of System.Windows.Forms.ToolStripItem) - Sets the list of controls that will be loaded into the menu for this filter.
  • Public Event UpdateFilter(ByVal sender As Object, ByVal e As i00BindingList.Plugins.UpdateFilterPluginEventArgs) - This should be raised when your controls cause the filter to be updated.

Below is an example of an iFilterPlugin that is used to filter a date range:

VB.NET
Public Class DateFilter
    Implements i00BindingList.Plugins.iFilterPlugin
 
#Region "Controls"
    'This is a Series of controls that will be available through the DataGridView's filter menu

    'This is the check box that when checked filters the dates as selected by the MonthCalendar,
    'This exists as the MonthCalendar has no way to have NO date selected...
    Private WithEvents tsiSelectDate As New i00BindingList.PersistentToolStripMenuItem() With {.Text = "Select a date or date range:"}
 
    'This is the month calendar that allows the user to select a date period to filter by
    Private WithEvents MonthCalendar As New MonthCalendar With {.MaxSelectionCount = Integer.MaxValue, .ShowTodayCircle = False}
 
    'Returns the controls back to the plugin that we want to add to the filter menu
    Public Function MenuItems() As System.Collections.Generic.List(Of System.Windows.Forms.ToolStripItem) Implements i00BindingList.Plugins.iFilterPlugin.MenuItems
        MenuItems = New List(Of ToolStripItem)
        Static ToolStripControlHost As New ToolStripControlHost(MonthCalendar)
        MenuItems.Add(tsiSelectDate)
        MenuItems.Add(ToolStripControlHost)
    End Function
 
#End Region
 
#Region "Data Specifications"
 
    'Returns an array of data types that we can use this filter on... in this case Date
    Public ReadOnly Property DataTypes() As System.Type() Implements i00BindingList.Plugins.iFilterPlugin.DataTypes
        Get
            Return New System.Type() {GetType(Date)}
        End Get
    End Property
 
    'Specifies when this plugin will be displayed
    'this is also, somewhat, controlled by the use of the i00BindingList.Plugins.ActiveFilterPlugins on the object property itself
    Public ReadOnly Property Dispaly() As i00BindingList.Plugins.DisplayMethods Implements i00BindingList.Plugins.iFilterPlugin.Dispaly
        Get
            Return i00BindingList.Plugins.DisplayMethods.DefaultShow
        End Get
    End Property
 
#End Region
 
#Region "Events"
 
    'This is raised when our controls cause the filter to be updated...
    'e.FilterBase is used to send back the BasicFilterBase that is created from the options selected from our controls
    Public Event UpdateFilter(ByVal sender As Object, ByVal e As i00BindingList.Plugins.UpdateFilterPluginEventArgs) Implements i00BindingList.Plugins.iFilterPlugin.UpdateFilter
 
#End Region
 
#Region "BasicFilterBase"
    'BasicFilterBase's basically allow the creation of "some-what automated" LINQ where statements, through the specification of certain parameters

    'This is a BasicFilter that will be used to create a LINQ where clause from based on data we will get from our controls
    Public Class BasicDateFilter
        Inherits i00BindingList.AdvancedBindingSource.BasicFilterBase
 
        'The data that we will be filtering on with our iFilterPlugin
        Public DateFrom As Date
        Public DateTo As Date
 
        'Generates a basic LINQ where statement from the prams above
        Public Overrides ReadOnly Property GetLinq() As String
            Get
                Return "CDate(Format(xItem.[" & Field & "], ""D"")) >= CDate(""" & DateFrom.ToString & """) AndAlso CDate(Format(xItem.[" & Field & "], ""D"")) <= CDate(""" & DateTo.ToString & """)"
            End Get
        End Property
    End Class
 
#End Region
 
#Region "Filtering"
 
    'This is called when the filter needs to be re-loaded
    'for example if the date 1/1/1 -> 2/2/2 is selected in a BasicDateFilter(Filter pram) we should update our controls to match this data
    Public Sub LoadFromFilter(ByVal Filter As i00BindingList.AdvancedBindingSource.BasicFilterBase) Implements i00BindingList.Plugins.iFilterPlugin.LoadFromFilter
        Dim BasicDateFilter = TryCast(Filter, BasicDateFilter)
        FireMonthCalendar_DateChanged = False
        If BasicDateFilter IsNot Nothing Then
            'we have an existing BasicDateFilter so load the control properties from that
            LastBasicDateFilter = BasicDateFilter
            MonthCalendar.SelectionRange = New SelectionRange(BasicDateFilter.DateFrom, BasicDateFilter.DateTo)
            tsiSelectDate.Checked = True
        Else
            'this field is not filtered (at least not with a BasicDateFilter), so load the default values...
            LastBasicDateFilter = Nothing
            tsiSelectDate.Checked = False
        End If
        FireMonthCalendar_DateChanged = True
    End Sub
 
    Dim FireMonthCalendar_DateChanged As Boolean = True
    Dim LastBasicDateFilter As BasicDateFilter
 
    'When our MonthCalendar is updated raise the UpdateFilter event so that the Plugin can re-filter the data
    Private Sub MonthCalendar_DateChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DateRangeEventArgs) Handles MonthCalendar.DateChanged, MonthCalendar.DateSelected
        If FireMonthCalendar_DateChanged Then
            Dim BasicDateFilter = New BasicDateFilter With {.DateFrom = MonthCalendar.SelectionRange.Start, .DateTo = MonthCalendar.SelectionRange.End}
            If LastBasicDateFilter Is Nothing OrElse (BasicDateFilter.DateFrom <> LastBasicDateFilter.DateFrom OrElse BasicDateFilter.DateTo <> LastBasicDateFilter.DateTo) Then
                RaiseEvent UpdateFilter(Me, New i00BindingList.Plugins.UpdateFilterPluginEventArgs() With {.FilterBase = BasicDateFilter})
                LastBasicDateFilter = BasicDateFilter
                tsiSelectDate.Checked = True
            End If
        End If
    End Sub
 
    'When the "Select a date or date range" option is checked call the MonthCalendar_DateChanged so that the Plugin can re-filter the data
    Private Sub tsiSelectDate_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles tsiSelectDate.Click
        tsiSelectDate.Checked = Not tsiSelectDate.Checked
        LastBasicDateFilter = Nothing
        If tsiSelectDate.Checked = True Then
            'filter
            MonthCalendar_DateChanged(MonthCalendar, New DateRangeEventArgs(MonthCalendar.SelectionRange.Start, MonthCalendar.SelectionRange.End))
        Else
            'unfilter
            RaiseEvent UpdateFilter(Me, New i00BindingList.Plugins.UpdateFilterPluginEventArgs())
        End If
    End Sub
 
#End Region
 
End Class

The above code will produce the following:

Image 5

Downloads

Total Downloads: Image 6

Downloads per day:
Image 7

Change Log

20120723

  • Fixed a bug that when canceling an edit (eg. in a DGV) on an existing row on the Binding List would delete the item!

20120719

  • Made properties / functions etc of the BindingListView use T instead of object .. eg: Item(ByVal Index As Integer) As T
  • AddRange added to BindingListView
  • Added AddingFilterPlugin event to DataGridView that allows programmers to cancel the plugin from being loaded, or modify plugin settings
  • Fixed a bug where the custom filter plugins would filter the data multiple times instead of just once
  • Changed Filter Linq query structure to remove requirement for "From xItem in ..."
  • Changed Filter Linq query structure so that you can just specify the fields with "[field]"

Thanks

Thanks for downloading.

Suggestions on possible improvements are much appreciated.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)