Перемещение по ListView WPF стрелочками

private List<MyObject> o = new List<MyObject>();

...
listView.ItemsSource = o;
...
//потом добавляем элементы в `o` и делаем `listView.Items.Refresh()

Если нажимать на клавиатуре вверх / вниз, можно перемещаться по элементам ListView.
Но если какое-то событие еще раз добавило элемент в o и вызвало listView.Items.Refresh();, то при нажатии любой стрелочки (даже влево или вправо) я оказываюсь на нулевом индексе (то есть, на первом элементе списка). Это офигеть как удобно. Просто новаторское решение.
Как это можно исправить?
При этом, после рефреша, свойство SelectedIndex в -1 не сбрасывается (что странно).

Обычно так не надо делать, надо использовать правильные коллекции.
How I Can Refresh ListView in WPF - Stack Overflow

No need to call ListView1.Items.Refresh() when you use ObservableCollection.

почему? :thinking:

Коллекция предоставляет события об изменениях, UI их использует.
Это скорее всего как минимум эффективнее рефреша всего содержимого.
И проще, удобнее. Не получится забыть рефрешнуть.

Не, а почему при использовании ObservableCollection рефреш не нужен? Я ведь никакой дополнительный код не прописываю и никакие события этой коллекции не использую.

Я ж говорю, оно само узнает об изменениях.

Хочу уточнить один момент. Есть вот такая модель:

    internal class Model
    {
        public int Index { get; set; }
        public int State { get; set; }
    }

XAML:

            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Index" Width="120" DisplayMemberBinding="{Binding Index}" />
                    <GridViewColumn Header="state" Width="170" DisplayMemberBinding="{Binding State}" />
                </GridView>
            </ListView.View>

код:

        private ObservableCollection<Model> items = new ObservableCollection<Model>();

.......

            listView.ItemsSource = items;
//..заполняем `items` сотней элементов.

Потом в каком-нибудь событии (например, в таймере) делаем:

items[randomInt].State = randomInt2;

При этом содержимое ListView должно обновиться само, без каких-либо дополнительных действий?
То есть, достаточно просто изменить данные в коллекции и они сразу отобразятся в ListView?

Для обнаружения изменений свойств еще нужен INotifyPropertyChanged.
How to: Implement Property Change Notification - WPF .NET Framework | Microsoft Learn

    internal class Model : Notifier
    {
        public int Index { get => _index; set => SetProperty(ref _index, value) }
        public int State { get => _state; set => SetProperty(ref _state, value) }

        private int _index;
        private int _state;
    }
    internal abstract class Notifier : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void SetProperty<T>(ref T propertyField, T newValue, [CallerMemberName] string propertyName = null)
        {
            if (!Equals(propertyField, newValue))
            {
                T oldValue = propertyField;
                propertyField = newValue;
                RaisePropertyChanged(propertyName);

                OnPropertyChanged(propertyName, oldValue, newValue);
            }
        }

        protected virtual void OnPropertyChanged(string propertyName, object oldValue, object newValue) { }
    }

А вот так можно? :thinking:
Короче, ок. Про ObservableCollection я понял. Но теперь вылезла другая проблема. Он элементы красит не тем цветом, какой указан в коде. Я этого сразу не заметил :thinking: Потому что с рефрешем такого не было, наверное :man_shrugging: