Click here to Skip to main content
15,891,764 members
Articles / Programming Languages / C#
Article

How To Allow To Sort By Multiple Columns in Custom Data Binding

Rate me:
Please Sign up or sign in to vote.
3.82/5 (6 votes)
4 Aug 2007CPOL2 min read 95.3K   2.4K   46   4
The description of how to realise the possibility of sorting by many columns in DataGridView if data source is a list of objects

Introduction

When you bind DataGridView to a custom business object, you probably want to allow to sort by column or by multiple columns. You are able to use BindingSource to bind your data, but this component does not realize sorting functions.

If you need to sort by one column only, you can use SortableBindingList described in the article: Custom Data Binding, Part 2.

But the technology used here does not allow to sort by multiple columns. This article describes how to add sorting functionality in a simple and fast manner. 

Background

When you want to bind DataGridView to your business logic objects, you typically use three steps:

  1. In design-time: Create specified DataSource type for your object (by selecting Data-Add new data source in the menu and by specifying your custom object as fields source; see Custom Data Binding, Part 1 for more details).
  2. In design-time: Create BindingSource component and specify created DataSource for its DataSource property.
  3. In runtime: Create the list of your specified type and assign it to the DataSource property of the BindingSource component.

In this case, you can't use BindingSource.Sort property because your List<...> will be automatically transformed to the BindingList<...>. To allow sorting by one or multiple columns DataSource should implement IBindingListView interface, but the created BindingList<...> does not implement it (as you can see in the BindinList realization):

C#
public class BindingList<T> : Collection<T>, IBindingList, IList, 
	ICollection, IEnumerable, ICancelAddNew, IRaiseItemChangedEvents

So, we need to implement IBindingListView to be able to sort by one or multiple columns. You can use the Sort property of the BindingSource then by specifying columns names and sort direction and using comma separator, e.g.:

C#
BindingSource.Sort = "Column1 ASC, Column2 DESC, Column 3 ASC"; 

So, I have created MultipleSortableBindingListView class to implement IBindingListView interface:

C#
public class MultipleSortableBindingListView<T> : BindingList<T>, IBindingListView 

Using the Code

Let's imagine, that we have a Person class and list of objects to be displayed on the DataGridView:

C#
public class Person {...} 
public List<Person> list = ...;

Now you should use MultipleSortableBindingListView<Person> instead of List<Person>. As you can see, BindingList (and MultipleSortableBindingListView too) implements IList. Thus, you do not need to change your logic to create the list of Persons to be displayed: our new class has methods as List class.

The next step is to enjoy! Now MultipleSortableBindingListView<...> will be used when BindingSource.DataSource is assigned to a list variable, and you can enjoy with the Sort property of the BindingSource component. It works!

Points of Interest

I have used PropertyComparer class from Custom Data Binding, Part 2, and I have hardly changed it to allow to compare different basic values and reference type properties.

Next...

The next good point is to add filtering functions from Custom Data Binding, Part 3 to our class if you need it.

History

  • 5th August, 2007: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionError in PropertyComparer? Pin
ConradsWa14-Nov-08 12:07
ConradsWa14-Nov-08 12:07 
GeneralSorting, small glitch Pin
pinx20-Feb-08 5:10
pinx20-Feb-08 5:10 
Question...How is it in VB ??? Pin
Croghen9-Nov-07 1:42
Croghen9-Nov-07 1:42 
AnswerRe: ...How is it in VB ??? Pin
pinx4-Dec-07 4:21
pinx4-Dec-07 4:21 
Imports System.ComponentModel



Public Class MultipleSortableBindingListView(Of T)

Inherits BindingList(Of T)

Implements IBindingListView



Private _SortDescriptions As ListSortDescriptionCollection

Private comparers As List(Of PropertyComparer(Of T))



Public Sub New()

MyBase.New()

End Sub

Public Sub New(ByVal list As System.Collections.Generic.IList(Of T))

MyBase.New(list)

End Sub

Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean

Get

Return True

End Get

End Property

Public ReadOnly Property SortDescriptions() As ListSortDescriptionCollection Implements IBindingListView.SortDescriptions

Get

Return _SortDescriptions

End Get

End Property



Public ReadOnly Property SupportsAdvancedSorting() As Boolean Implements IBindingListView.SupportsAdvancedSorting

Get

Return True

End Get

End Property



Private Function CompareValuesByProperties(ByVal x As T, ByVal y As T) As Integer

If x Is Nothing Then

If y Is Nothing Then

Return 0

Else

Return -1

End If

Else

If y Is Nothing Then

Return 1

Else

For Each comparer As PropertyComparer(Of T) In comparers

Dim retval As Integer = comparer.Compare(x, y)

If retval <> 0 Then

Return retval

End If

Next

Return 0

End If

End If

End Function



Protected Overrides Sub ApplySortCore(ByVal prop As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection)

Dim items As List(Of T) = TryCast(Me.Items, List(Of T))

If items IsNot Nothing Then

items.Sort(New PropertyComparer(Of T)(prop, direction))

End If

Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))

End Sub



Public Sub ApplySort(ByVal sorts As ListSortDescriptionCollection) Implements IBindingListView.ApplySort

' Get list to sort

' Note: Me.Items is a non-sortable ICollection<t>

Dim items As List(Of T) = TryCast(Me.Items, List(Of T))

' Apply and set the sort, if items to sort

If items IsNot Nothing Then

Me._SortDescriptions = sorts

Me.comparers = New List(Of PropertyComparer(Of T))()

For Each sort As ListSortDescription In sorts

Me.comparers.Add(New PropertyComparer(Of T)(sort.PropertyDescriptor, sort.SortDirection))

Next

items.Sort(AddressOf CompareValuesByProperties)

End If

Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))

End Sub



Public Property Filter() As String Implements System.ComponentModel.IBindingListView.Filter

Get

Return String.Empty

End Get

Set(ByVal value As String)

End Set

End Property



Public Sub RemoveFilter() Implements System.ComponentModel.IBindingListView.RemoveFilter

End Sub



Public ReadOnly Property SupportsFiltering() As Boolean Implements System.ComponentModel.IBindingListView.SupportsFiltering

Get

Return True

End Get

End Property

End Class


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.