Which column tapped when didChangeSortOrderForColumn called


#1

If my grid is already sorted by one column, and I tap a second column willChangeSortOrderForColumn and didChangeSortOrderForColumn both get called twice. If I had tapped the same column that it was already sorted by, it would only have called willChangeSortOrderForColumn and didChangeSortOrderForColumn once.

I understand that it is calling the first column to update the the UI, telling it that it is no longer the active sort table, but is there a way to know that this is getting called as part of a two-call update and have only the second call do all of the lifting?

Basically, my code is being executed twice when I switch which column I am sorting by and I would like to be able to have it not do that.


#2

Hi canderson,

As you surmised, the delegate methods are called on the first column as well as the second because the order of both columns is changing. The sort order of the other sortable columns is reset to SDataGridColumnSortOrderNone before the new sort order is applied to the tapped column.

If your columns’ sort mode is SDataGridColumnSortModeBiState then you can just check the new sort order (i.e. the sortOrder parameter passed in to willChange... or the sortOrder of the column passed in to didChange...): if it’s SDataGridColumnSortOrderNone then you know that the delegate call is due to the column’s sort order being reset.

If your columns’ sort mode is SDataGridColumnSortModeTriState then you’ll need to differentiate between the case where the first column is returning to SDataGridColumnSortOrderNone due to a tap on its own header, and the case where it is changing its order due to the second column being reordered. In this case I’d suggest keeping a reference to the last sorted column to check against.

I hope that helps.

Kind regards,

Alison


#3

@aclarke Thanks for the reply.

My sort mode is indeed TriState, so my issue is indeed trying to differentiate between the cases of when it is the current column or a new column being selected. I am keeping track of what the current sort order is, but that still leaves me with an issue sometimes.

If column A is sorted in Desc order. No matter what I column I tap next, the next call is going to switch column A to None. So without additional information, I still don’t know which header was tapped.


#4

If your only concern is that the code is executed only once, I think you can do something like this:

  • Create a lastSortedColumn variable, initially nil
  • At the start of willSort... and didSort..., execute your code only if lastSorted is nil or is the same as the column passed in
  • At the end of didSort..., set lastSorted to be the column passed in

So in the case you mention, lastSorted will be column A, then if you tap column B, the code will execute when column A is reset, but not when column B is sorted.

If you need to know exactly which column has been tapped then please let us know more about what you’re trying to achieve so we can try to find a different solution.


#5

Yeah, that wouldn’t work for my case. I need to know that column B is the one that wants to be sorted.

What my code has been doing is when didSort gets called, it checked to see what column it is and if it is the previous column. If it was the previous column and it is the next expected order (so ASC>DESC>NONE) it assumes that it was tapped and calls the sort method (sometimes this is locally handled, sometimes this is passed to the server.) If it was a column other than the previously selected column, it knows that it is a newly selected column and will sort by that.

So the only time there is an issue is if column A is DESC and you tap column B (or C, D, etc). Column A flips to NONE which is the next expected order, so it calls its sort method. Immediately after, column B calls its sort method. This causes a race condition where the results come back and populate the table. Sometimes column A results will come back after B’s so the table gets populated with them. The control still shows that B is the column that is sorted by (one of the arrows is filled) but this may not match the data.

For now, my work around is to just ignore None sorts. Previously none would allow the data to return to it’s previously unsorted state (or something similar depending on context.)


#6

Are you following the pattern in the How to: Sort the Shinobi DataGrid section of the User Guide?

I’m trying to figure out what’s causing the race condition, as it’s not something we’ve seen before: is your sort taking a long time or happening in a different thread?


#7

I believe I am following that pattern for the most part. This code was written several years ago, and the issue hadn’t popped up enough to get my attention until recently. But yes, since I am having to pass off the sorting to the server, it could take a long time and is being handled in a separate thread.

It is in Xamarin (but obviously it mimics how the Objective C code works.)

I have recently changed from using OnChanged to OnChanging, but the logic still follows. Here is the basic layout of my code on my delegate.

protected override void OnChangedSortOrderForColumn (ShinobiDataGrid grid, SDataGridColumn column, SDataGridColumnSortOrder oldSortOrder)
{
 ...
bool shouldChange = false;
if (lastColumn != column) {
   shouldChange = true;
} else {
    if (oldSortOrder == nextSortOrder) {
	//next order matches the oldSortOrder so we may have clicked the same header twice
	shouldChange = true;
    }

}
if(shouldChange){
 if (SortChangedAction != null) {
	SortChangedAction (grid, column, oldSortOrder);
}

}
}

SortChangedAction changes depending on the table, but in the scenarios where I am having this issue it takes the information about the sorted column and order and makes an asynchronous call to the server. When the server replies those rows are populated into the datagrid’s datasource. When two calls are made, I get two separate calls to the server and two separate replies.


#8

Thanks for the reply. I see the issue now, and I don’t think there’s anything in the grids API itself that could help.

However, is it be possible to modify your SortChangedAction so that when the server returns the sorted data, the callback also know which column was just sorted? It could then compare that to lastColumn/nextSortOrder, and only update the grid’s datasource if they match?


#9

I can certainly look into that as a solution. Thanks for the help.