datagridview sortable binding list how can I have a secondary sort?

I implemented a sortable binding list which can be found here:  

I bind the object to my grid like the code below.  This works well. I have a date column, which I would like to be the secondary sort though.  So if you sort by title, I want to sort by title then date.  How can I do this?

SortableBindingList<UnassociatedTradeView> filtered = new SortableBindingList<UnassociatedTradeView>(listBinding.Where(obj => !associatedTradeIds.Contains(obj.orderNumber)).ToList());
dataGridUnassociatedTrades.DataSource = filtered;

foreach (DataGridViewColumn column in dataGridUnassociatedTrades.Columns)
dataGridUnassociatedTrades.Columns[column.Name].SortMode = DataGridViewColumnSortMode.Automatic;
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jackjohnson44Author Commented:
Please do not post generic links!
Jacques Bourgeois (James Burger)PresidentCommented:
You need to create a class that implements System.Collections.IComparer, and use an instance of that class as a parameter to the Sort method of the grid. Here is a real life example. It's in VB, but the technique is the same in C#.
	Private Class DocumentationComparer
		Implements System.Collections.IComparer

		'Used to sort multiple columns together in the FormDocumentation grid

		Public Sub New(columnToSort As Integer, direction As SortOrder)
			_columnToSort = columnToSort
			_direction = direction
		End Sub

		Public Function Compare(x As Object, y As Object) As Integer Implements System.Collections.IComparer.Compare

			Dim result As Integer
			Dim rowX As DataGridViewRow = DirectCast(x, DataGridViewRow)
			Dim rowY As DataGridViewRow = DirectCast(y, DataGridViewRow)

			Select Case _columnToSort

				Case FormDocumentation.ColumnsID.SubjectID
					'Subject is always sorted in parallel with the Description
					If CInt(rowX.Cells(FormDocumentation.ColumnsID.SubjectID).Value) = CInt(rowY.Cells(FormDocumentation.ColumnsID.SubjectID).Value) Then
						'We sub-sort on the Description
						result = String.Compare(CStr(rowX.Cells(FormDocumentation.ColumnsID.Description).Value), CStr(rowY.Cells(FormDocumentation.ColumnsID.Description).Value))
						'We sort on the Subject
						result = String.Compare(CStr(rowX.Cells(FormDocumentation.ColumnsID.SubjectID).FormattedValue), CStr(rowY.Cells(FormDocumentation.ColumnsID.SubjectID).FormattedValue))
					End If

				Case FormDocumentation.ColumnsID.SourceID
					'Subsort the issue and page for the Source
					If CInt(rowX.Cells(FormDocumentation.ColumnsID.SourceID).Value) = CInt(rowY.Cells(FormDocumentation.ColumnsID.SourceID).Value) Then
						'We sub-sort on the Issue
						If CStr(rowX.Cells(FormDocumentation.ColumnsID.IssueUrl).Value) = CStr(rowY.Cells(FormDocumentation.ColumnsID.IssueUrl).Value) Then
							'We sub-sort on the Page
							result = CInt(rowX.Cells(FormDocumentation.ColumnsID.Page).Value).CompareTo(CInt(rowY.Cells(FormDocumentation.ColumnsID.Page).Value))
							'We sort on the Issue
							result = String.Compare(CStr(rowX.Cells(FormDocumentation.ColumnsID.IssueUrl).Value), CStr(rowY.Cells(FormDocumentation.ColumnsID.IssueUrl).Value), StringComparison.CurrentCulture)
						End If
						'We sort on the Source
						result = String.Compare(CStr(rowX.Cells(FormDocumentation.ColumnsID.SourceID).FormattedValue), CStr(rowY.Cells(FormDocumentation.ColumnsID.SourceID).FormattedValue), StringComparison.CurrentCulture)
					End If

				Case Else
					'The other columns are sorted on their content
					result = String.Compare(CStr(rowX.Cells(_columnToSort).FormattedValue), CStr(rowY.Cells(_columnToSort).FormattedValue), StringComparison.CurrentCulture)

			End Select

			If _direction = SortOrder.Ascending Then
				Return result
				'We need to inverse the result
				Return -result
			End If

		End Function

	End Class

Open in new window

Note that you can make it a lot simpler, I will come back to that at the end of my post.

But in my case, but in my case, I needed to be able to sort on different columns and did not want to have to create a class for each sort. I thus pass parameters to the constructor (New method in VB) telling the class on which column to sort and in which order, and coded so that the same class came be used for different columns.

The class does not perform the sort. It simply tells the grid how to go about comparing 2 rows. This is done in the Compare method, that will be called repetitively by the grid sorting mechanism with sets of 2 rows. All you have to do is to return a value less than zero if the first row should come before the second one, zero if they are seen as equal, and greater than zero if the first if the second one should come first.

The Select Case makes a difference between sorting on a SubjectID column, a SourceID column, and all the other columns that do not have a special sort. The FormDocumentation.ColumnsID enumeration that defines the index of the columns in the grid, so I am basically working with the column indexes here to retrieve the values to sort on. You could use the column names, but that method can be called hundreds of times to sort a big grid, and working with the indexes is a lot faster.

My code works with a grid that displays references in a collection of magazines. The second Case, on FormDocumentation.ColumnsID.SourceID is a multi-column sort. When the user wants to sort by magazine (SourceID), and when the method is sent 2 rows with the same magazine name, it sorts first by magazine name (SourceID), then the Issue (IssueID), and then by the page number. Integers and Strings already have Compare methods that work exactly on the same concept as the one we are defining here, so I use them to return the appropriate "less than zero / zero / greater than zero" values.

When you need to sort the grid, all you have to do is the following:

YourGrid.Sort(New DocumentationComparer(<Index of the column I want to sort>,<SortOrder>))

If you need only one type of sort for the grid, then everything can be a lot simpler. You do not need to create a constructor that receives parameters and do not need the Case in the Compare method, only your single algorithm. The method sort can then be called simply by YourGrid.Sort(New <YourComparerClass>)

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jackjohnson44Author Commented:
Thanks, that was detailed!
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.