Обратиться к коллекции по событию в MVVM

Model:

namespace WPF_MVVM.Models
{
    public class Model : Notifier
    {
        public string Name { get => _name; set => SetProperty(ref _name, value); }
        public int Id { get => _id; set => SetProperty(ref _id, value); }

        private string _name;
        private int _id;
    }
}

ViewModel:

using System.Collections.ObjectModel;

namespace WPF_MVVM.Models
{
    internal class ViewModel
    {
        public ObservableCollection<Model> items { get; set; }

        public ViewModel()
        {
            items = new ObservableCollection<Model>()
            {
                new Model() { Name = "User1", Id = 1 },
                new Model() { Name = "User2", Id = 2 }
            };
        }
    }
}

Notifier:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPF_MVVM
{
    public 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) { }
    }
}

XAML:

<Window x:Class="WPF_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="clr-namespace:WPF_MVVM.Models"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <vm:ViewModel />
    </Window.DataContext>

    <Grid>
        <StackPanel>
            <DataGrid ItemsSource="{Binding items}">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                    <DataGridTextColumn Header="ID" Binding="{Binding Id}" />
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Grid>
</Window>

Как в таком MVVM обращаться к коллекции по событию? Например, по таймеру каждую секунду добавлять в коллекцию новый элемент.
Говорят, что, по-хорошему, код окна должен быть пустой. То есть, там не должно быть никаких обработчиков. А как тогда?
Да, я знаю, что есть, так называемые, “команды”. Но как с их помощью решить даже такую простую задачу - понятнее не становится.

Таймер и так не особо имеет отношение к окну. Просто запустить его где-нибудь и менять items.

А про команды есть же много примеров:
WPF ICommand In MVVM
MVVM - Commands, RelayCommands and EventToCommand | Microsoft Learn

Да, но как сделать логику типа “при запуске программы загрузить конфиг, создать таймер, ещё что-то создать, и бла-бла-бла”? :thinking:
То есть, это всё в конструкторе вью-модели? У других классов ведь нет доступа к коллекции. Она не доступна нигде, кроме как во вью-модели.