Thanks for posting the timings along with the code, that made this easy to chase down. I can reproduce your numbers almost exactly: on my test machine, the same loop shape takes about 12 seconds with 100,000 rows and 5,000 selected, and about 29 seconds with 10,000 selected.
The cost is not in SetCellChecked. It is in SelectedRowIndex(n): each call rebuilds the full list of selected row indexes by walking every row in the ListBox, so looping over 5,000 selected rows out of 100,000 ends up touching each row 5,000 times. That is also why the time grows much faster than the number of selected rows.
Workaround for the current release
Read the selected indexes once with SelectedRowIndexes and loop over that array instead. For your btn_SelectOne case:
Var v_selected As Array(Of Integer) = p_listbox.SelectedRowIndexes
For i As Integer = 0 To v_selected.Count - 1
Var v_row As Integer
v_row = v_selected[i]
p_listbox.SetCellChecked(v_row, 0, True)
Next i
The same change with False covers btn_RemoveOne. In my measurements this brings the operation from roughly 12 seconds down to a few milliseconds, because the selected indexes are resolved in a single pass instead of once per iteration.
Fixed for the next release
I've also fixed the underlying cause, so the loop exactly as you posted it will be fast on its own: SelectedRowIndex(n) now reuses the resolved index list until the selection or the row list actually changes. The 100,000-row, 10,000-selected case that took about 29 seconds now completes in milliseconds here.
Tracked at https://feedback.objo.dev/feature/1706 and shipping in the next Studio release. One related improvement that may matter for your workflow: multi-selections now also survive InsertRow and RemoveRow in code (https://feedback.objo.dev/feature/1707), so selecting rows, ticking them, and then removing them keeps the rest of the selection intact.