Search code examples
dynamic-datareactiveui

ObservableChangeSet wait until list is ready before watching


We have a list page where we can enable or disable a thing™ using a <switch /> That thing™ is toggled with an IsActive flag

public class Thing
{
    /* ... */
    [Reactive] public bool IsActive { get; set; }
}

Given the following change listener, the idea is when the IsActive property changes (user interaction on a toggle switch), we invoke the _saveItemCommand to save the entity with the new IsActiveState.

public ObservableCollection<Thing> DataObjectList {get;} = new ObservableCollection<Thing>();

public MyClass()
{
    _saveItemCommand  = ReactiveCommand.CreateFromTask(SaveItemInternal);
    _listWatcher = DataObjectList
        .ToObservableChangeSet()
        .AsObservableList()
        .Connect()
        .WhenPropertyChanged(x => x.IsActive)
        .Throttle(TimeSpan.FromMilliseconds(250))
        .ObserveOn(RxApp.MainThreadScheduler)
        .Select(x => x.Sender)
        .InvokeCommand(_saveItemCommand);
}

public void OnNavigatingTo()
{
    var newItems = _myService.GetNewItems();
    DataObjectList.AddRange(newItems);
}

public void OnDestroy()
{
    _listWatcher?.Dispose();
}

The problem I'm having is that when I setup the list, The command seems to be invoked on the last item in the list immediately after AddRange is called.

I have tried using .Skip(1) without any luck, but one thing that seems to work but is ugly is .Skip(DataObjectList.Length)

How can I make it so that the command isn't invoked until the first time the user toggles the switch? What is the correct way to setup this listener?


Solution

  • After the comments on Glenn's answer and some additional conversations with Rodney, here's what finally works.

    _listWatcher = DataObjectList
        .ToObservableChangeSet()
        .AsObservableList()
        .Connect()
        .WhenPropertyChanged(x => x.IsActive)
        .Throttle(TimeSpan.FromMilliseconds(250))
        .Skip(1)
        .DistinctUntilChanged()
        .ObserveOn(RxApp.MainThreadScheduler)
        .Select(x => x.Sender)
        .InvokeCommand(_createActivationsInternal);