Updates and selection

Keep collection snapshots current and respond to selection and scroll position.

Use ObservableCollection<T> when collection membership changes after the view appears:

public ObservableCollection<Contact> Contacts { get; } = [];

void Add(Contact contact) => Contacts.Insert(0, contact);
void Remove(Contact contact) => Contacts.Remove(contact);
void MoveToTop(Contact contact) => Contacts.Move(Contacts.IndexOf(contact), 0);

SkeleKit coalesces source changes into animated native snapshots. Mutate the collection on the main thread. Bind item properties through INotifyPropertyChanged when the row stays in place but its displayed values change.

See data and templates for the distinction between item identity, membership changes, and bound property changes.

Taps and highlights

ItemCommand runs with the tapped item:

new CollectionView<Contact>
{
    ItemsSource = viewModel.Contacts,
    ItemTemplate = static () => new ContactRow(),
    Layout = CollectionLayout.List(),
    ItemCommand = viewModel.OpenContactCommand,
    HighlightsSelection = true,
    HighlightColor = Colors.Indigo.WithAlpha(0.12)
};

HighlightsSelection keeps the native selection highlight until the page appears again. Disable it for cards or controls where a retained row selection would be misleading. HighlightColor replaces the system gray.

Empty state

EmptyView replaces the collection content while the active source has no items. It is a SkeleKit view, so it can contain a retry command or progress state rather than only text.

Scrolling

Scrolled reports the vertical offset. Call ScrollTo(item, position, animated) to bring an existing item into view:

contacts.ScrollTo(
    selectedContact,
    ScrollPosition.Center,
    animated: true);

The requested object must be the same instance present in the source. ScrollPosition.Top, Center, and Bottom choose its alignment.

Loading near the end

Set LoadMoreCommand and LoadMoreThreshold to request another page before the user reaches the final item. The command fires once for a given item count. Adding results enables another request when the new end approaches; leaving the count unchanged prevents an immediate loop.

Keep a ViewModel loading flag and make the command's CanExecute reflect it so concurrent requests cannot overlap.

Pull-to-refresh, swipe actions, context menus, and edit mode are covered in refresh and editing.