Situation:
I have a grid with columns "NAME" and "DATE". When sorting (ascending) on date, all rows without a date should be placed at the end of the rowcollection (like when sorting descending).
This is what i'm currently doing:
Private Sub gridcandidates_AfterSortChange(ByVal sender As System.Object, ByVal e As Infragistics.Win.UltraWinGrid.BandEventArgs) Handles gridcandidates.AfterSortChange
Dim col As UltraGridColumn = e.Band.Columns("DATE") If col.SortIndicator = SortIndicator.Ascending Then For i As Integer = gridcandidates.Rows.Count - 1 To 0 Step -1 If Not IsDBNull(gridcandidates.Rows(i).Cells("DATE").Value) Then gridcandidates.Rows.Move(gridcandidates.Rows(i), 0) 'Move row to beginning Else gridcandidates.Rows.Move(gridcandidates.Rows(i), gridcandidates.Rows.Count - 1) 'Move row to end End If Next End If
End Sub
Question/problems:
- It messes up the sort... the columns aren't sorted by date.
- Is there anyway to improve the code? I'm sure i'm overlooking something!
I think the actual sorting process may be asynchronous, so the rows might not actually be sorted by the time AfterSortChange fires.
You might be better off applying a SortComparer to the column. Your custom SortComparer class would have to know whether the column is being sorted Ascending or Descending (you could set a property on it from the BeforeSortChange event of the grid) and then sort the null values as higher or lower depending on the sort direction.
I'll give it a try!
Thanks Mike
This works:
public int Compare(object x, object y) { UltraGridCell xCell = x as UltraGridCell; UltraGridCell yCell = y as UltraGridCell; object xObject = xCell.Value; object yObject = yCell.Value; // If the two values are the same, compare the row index. // This isn't really neccessary, but it makes the sorting more reliable. // We won't get random switching of like values when sorting multiple // times. if (xObject.Equals(yObject)) return xCell.Row.Index.CompareTo(yCell.Row.Index); // If we get to this point, we know the values are not equal. So if // the x value is null, we know the y value is not. if (xObject is DBNull || xObject == null) { // If we are sorting ascending, then null is greater than any other // value. If we are sorting descending, null is less that any other // value. return ascending ? 1 : -1; } // If we get to this point, we know the values are not equal. So if // the y value is null, we know the x value is not. if (yObject is DBNull || yObject == null) { // If we are sorting ascending, then null is less than any other // value. If we are sorting descending, null is greater that any other // value. return ascending ? -1 : 1; } // If we get here, there are no nulls and the values are not equal // so just compare them as ints. int xInt = (int)xObject; int yInt = (int)yObject; return xInt.CompareTo(yInt); }
Just a note on the following section of code:
// If the two values are the same, compare the row index. // This isn't really neccessary, but it makes the sorting more reliable. // We won't get random switching of like values when sorting multiple // times. if (xObject.Equals(yObject)) return xCell.Row.Index.CompareTo(yCell.Row.Index);
If you use this then the Group By function does not work correctly. It will think each item is different and won't group together the same items. If this is a problem for you then replace that section of code with:
if (xObject.Equals(yObject)) return 0;
This indicates that the objects are the same and the Group By function will work again.
The code you are referring to is there so that the sorting is never arbitrary. Without that peice of code, what happens is that when you have a group of rows with the same value, they will be sorted in essentially random order. This means if you sort the same column twice, the rows with values that are the same will come out in a different order each time.
A better solution to the GroupBy problem might be to use a customer GroupByEvaluator, rather than relying on the SortComparer to determine equality of columns. But quite frankly, I'm surprised the grid looks at the SortComparer for grouping, anyway.
I understand what it is for, I just wanted to point out that it breaks the group by. I wasn't expecting that, so I thought it was worth pointing out.
Hi Martin,
Yeah, it was a good tip. I wasn't contradicting you, just wanted to explain in more detail why that line of code was there so everyone understands the ramifications of changing it.
I, too, find it surprising that the GroupBy functionality uses the SortComparer on the column to determine equality when grouping.