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.