This project is read-only.

custom sort

Sep 5, 2009 at 10:39 PM


I need to custom sort my grid, I'd appreciate any help on the matter.

Let's say I have 10 columns and I need to sort on three of them. One of the sort columns cannot be sorted on it's actual value but by derived value, so I can't use the multicolumns sort as is.



Sep 6, 2009 at 7:27 AM

What help do you need exactly?

Sep 11, 2009 at 12:48 PM

Thank's for the quick reply...

I guess I just need to know how to treat the rows collection as somthing sortable.

How do I move a row to a new place in the collection?



Sep 15, 2009 at 7:23 AM

Well, if you use SourceGrid.Grid, then Rows property has a method to swap two rows. You could use that to implement sorting algorithm.

Sep 18, 2009 at 3:50 PM
Edited Sep 19, 2009 at 2:33 PM

for whom it may concern...

I figured it out at last and I give my solution here. Maybe it will help someone.

The grid has a SortRangeRows method that sorts a range of rows in the grid by the values of the sort column you hand it, and using a comparer class you give it.

Any custom work you need to do may be done in the comparing method of this class.

This comparing function is called for each iteration of the sort algorithm and is handed two cells to compare. If the cells are equal it must return 0 if the first is greate then it must return 1. if the first is lower it must return -1. All that for an ascending sort of course. reverse for descending sort.

Thats the simplest case. Ofcourse you can decide not to use the actual values of the cells to determine the sort order. You can determine that if cell 1 is 7 it will always be lower the the other cell, or in other words you can map the actual values of the cells to other set of values, then compare and return whatever is the outcome of this compare.

For more complicated custom sort you can get from the cells the grid that contains the cells and the row of each cell. From here you can get to other cells on the row(s) and decide what to return according to more then 1 pair of cells. Thats demonstrated in the MultyColumnComparer method of the grid.

To sum it all here are two versions of custom sorting. The first using the grid SortRangeRows. And theres  another that's using a modification of that method that is simpler and better suits my needs.

I call the sorting procedures form an onclick event handler of a button on my form.

First using the SortRangeRows

      public void SortBillDetails0() //sort using the SortRangeRows method of Grid
        IComparer detailsComparer = new BillDetailComparer2(myGrid); //this is the comparer that actually does the custom work
        myGrid.SortRangeRows(new SourceGrid.Range(1, 0, myGrid.Rows.Count - 1, _myGrid.Columns.Count - 1), 1, true, detailsComparer);

    public class BillDetailComparer2: IComparer
      //copied from SourceGrid\Common\Utilities.cs MultiColumnsComparer

      private IComparer _defaultComparer = new SourceGrid.ValueCellComparer();
      private SourceGrid grd;

      public BillDetailComparer2(SourceGrid gridToSort)
        grd = GridToSort;

      public virtual System.Int32 Compare(System.Object x, System.Object y)
        //for this custom sort I first get the value of column 2 in each row
        //this value determines the sort order. for certain value use columns 2,1,3 to sort, for other value use 1,3,2 and for nother value
        //use columns 1,2,3
        //thats the meaning of custom...
        int result;
        int[] sortColumns;

        int rowX = ((SourceGrid.Cells.ICell) x).Range.Start.Row;
        int rowY = ((SourceGrid.Cells.ICell) y).Range.Start.Row;

        int debitTypeX = (int) ((SourceGrid.Cells.Cell) grd.GetCell(rowX, 2)).Value;
        int debitTypeY = (int) ((SourceGrid.Cells.Cell) grd.GetCell(rowY, 2)).Value;
             debitTypeX == 4 || debitTypeX == 5 || debitTypeX == 6
          || debitTypeY == 4 || debitTypeY == 5 || debitTypeY == 6
          sortColumns = new int[] { 2, 1, 3 };
        else if (debitTypeX == 7 || debitTypeY == 7)
          sortColumns = new int[] { 1, 3, 2 };
          sortColumns = new int[] { 1, 2, 3 };

        for (int ixKeys = 0; ixKeys < sortColumns.Count(); ixKeys++)
          SourceGrid.Cells.ICellVirtual cellX = grd.GetCell(rowX, sortColumns[ixKeys]);
          SourceGrid.Cells.ICellVirtual cellY = grd.GetCell(rowY, sortColumns[ixKeys]);
          if (sortColumns[ixKeys] == 2 /*debit type column*/)
            //when sorting on debit type column - dont use the actual debit type id value - rather, use a show order for the debit type = 1,2,3,7,6,4,5
            result = _defaultComparer.Compare(DebitType.ShowOrder(debitTypeX), DebitType.ShowOrder(debitTypeY));
            result = _defaultComparer.Compare(cellX, cellY);

          if (result != 0)
            return result;

        //tried all sort columns and they are all equal = the lines are equal sortingwise
        return 0;

I decided at last to use a modified vesrion of the SortRangeRows method, because it is simpler and I always like my programs to do the least
necessary work so...
      public void SortBillDetails() //sort using a simple adaptation of SortRangeRows
        IComparer detailsComparer = new BillDetailComparer2(myGrid);

        RowInfo[] rowsToSort = new RowInfo[myGrid.Rows.Count - 1];
        SourceGrid.Cells.ICell[] cellKeys = new SourceGrid.Cells.ICell[myGrid.Rows.Count - 1];

        for (int r = 1; r < myGrid.Rows.Count; r++)
          cellKeys[r - 1] = myGrid[r, 0]; //get any cell it does not matter because the key array is sorted according to other cells - it's all on the detailsComparer
          rowsToSort[r - 1] = myGrid.Rows[r];

        Array.Sort(cellKeys, rowsToSort, 0, cellKeys.Length, detailsComparer);

        //Apply sort
        for (int ix = 0; ix < rowsToSort.Length; ix++)
          myGrid.Rows.Swap(rowsToSort[ix].Index, ix + 1);

thats it.