The two row spaces

The idea to have straight before you write anything larger.

In a sorted table, "row 7" means two different things. Keeping those two apart is what lets selection, sorting and filtering all work at the same time.

YOUR MODELTHE TABLETHE SCREENNaturalnever movesrow 7 is row 7after any sortSort orderplus a filter maskthe table owns thisyou cannot change itPresentedwhat is drawna sort gives no rowa new number

Natural

This is your numbering. Row 7 is row 7 whatever is sorted or filtered. Every call the table makes into your model uses it, and every row number it hands back is one of these.

Notify Row Changed (7) means the same row before a sort and after it, so you never have to track where a row moved to.

Presented

This is what is on screen: your rows filtered, and the ones left put in sort order. It is what the list draws, and it is what somebody means when they say "the third row".

The table owns this one and a model cannot change it.

What the split buys

A sort gives no row a new number, so nothing you stored goes stale. A selection lives through a sort because it was never a screen position in the first place. And a filter hides rows without renumbering the ones behind it.

Going between them

Presented To Natural Row answers "what is the third row on screen". Natural To Presented Row goes the other way, and returns -1 while a filter is hiding the row.

If you find yourself reaching for these a lot, something is usually being stored in the wrong space.

Next: Dropping to C++