SettlePolicy class Core
When a row is allowed to MOVE.
Sort a live grid by the column that changes fastest and it becomes technically correct and completely unusable: rows swap places several times a second, so you cannot click one — it is no longer where you saw it — and you cannot read a list that rearranges itself while your eye travels down it. Every value on screen is right, and the thing is useless.
So the two are separated. VALUES update at once: the numbers are always current. POSITIONS are held back for an interval and then applied as ONE batch, so the list rearranges in visible steps instead of continuously. That distinction is the most important usability decision in this whole strand, and it is a decision rather than a derivation — the right interval can only be found at a running feed, which is why the default is zero and the demo has a dial.
Throttled from the FIRST pending move, not debounced from the last. Debouncing reads better and starves: under a feed that never stops, "no change for 150 ms" never happens, and the order would simply never be applied.
Time is injected, never read — the same rule the animators follow, and what makes this testable without waiting.
public sealed class SettlePolicy
- Namespace
- ArionUI.Core
- Package
- ArionUI.Core ·
dotnet add package ArionUI.Core --prerelease
Constructors
SettlePolicy
public SettlePolicy();
Properties
IntervalMs
public double IntervalMs { get; set; }How long a row's move is held back, in milliseconds. 0 — the default — moves immediately, which is what the grid did before this existed: nobody gets a changed behaviour they did not ask for.
IsActive
public bool IsActive { get; }Is anything holding moves back at all? False means the caller should just apply the change and not pay for any of this.
PendingCount
public int PendingCount { get; }
Suspended
public bool Suspended { get; set; }Hold every move regardless of the interval, because something is going on that a rearranging list would ruin — an open editor, a drag, an open list the user is reading.
Methods
Clear
public void Clear();Forget everything pending — the row indices it holds have stopped meaning anything (a structural change moved them).
IsDue
public bool IsDue(double nowMs);Has the interval elapsed? Suspended never has.
Mark
public void Mark(int sourceIndex, double nowMs);Remember that this row wants to move. The clock starts on the FIRST one.
Take
public int Take(out int[] rows);Take the rows whose moves are owed and reset the clock. Returns how many were written into rows — a reused buffer, because settling happens on a timer and an allocation per settle is an allocation nobody asked for.
