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
Hi
I am trying to do the same thing. I created a NullValueComparer class and assigned to the relevant column. The column contains integer values but some values are null, and I want the null value records to always appear after the records with values. However, the records with null values still appear intermittently throughout the grid, and the numerical values are not sorted properly either. The _ascending value is set in the BeforeSortChange event. Here is the code I am using:
{
// Passed in objects are cells. So you have to typecast them to UltraGridCell objects first.
UltraGridCell yCell = (UltraGridCell)y;
// Compare values of xCell and yCell and return a negative
// number if xCell is less than yCell, positive number if xCell is greater than yCell,
// and 0 if xCell and yCell are equal.
// Regardless of whether the sort is ascending or descending, we want the null values to
// always appear at the bottom
// If the sort is ascending, null values should be set to larger than non-null values
// If the sort is descending, null values should be set to smaller than non-null values
// Extract values from cells
if (string.IsNullOrEmpty(xCell.Value.ToString()))
else
}
if (string.IsNullOrEmpty(yCell.Value.ToString()))
// Compare values
// want xValue to appear after actual values if ascending, therefore xValue greater than yValue
return 1;
// want yValue to appear after actual values if ascending, therefore yValue greater than xValue
if (xValue < yValue) return -1;
Can you please help me see what I am missing here?
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); }
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.
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.
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.
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.
Works great, thanks! I just had to switch around the return values in the line "return ascending ? 1 : -1;" to make it work for me. I had guessed it had something to do with the switching/sorting. Thanks again!