Search code examples
c#wpfobservablecollectionreactiveui

ObserableCollection not triggering Change when Items are added/removed from list


I have a problem with ReactiveUI ObservableCollection. I am trying to update the UI based on a list that changes in a ReactiveObject, but for some reason my list change is not triggered and I am not sure what I am doing wrong.

There is a full repo here : https://github.com/SebiCiuca/ObserableCollection

App has a button, that when it's clicked calls a "RandomService" that removes items from a list and then adds a random number of items back into the list.

This list is an ObservableCollection that has a Subscribe on it, so I would like to see in my ViewModel that the list change happening in RandomService is triggering my ObservableCollection ModelList change.

Code below:

MainWindow

     public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{
    public MainWindow(MainWindowViewModel mainWindowViewModel)
    {
        InitializeComponent();

        ViewModel = mainWindowViewModel;

        DataContextChanged += (sender, args) => ViewModel = DataContext as MainWindowViewModel;

        this.WhenActivated(cleanup =>
        {
            this.BindCommand(ViewModel, vm => vm.RandonListCommand, view => view.RandomButton).DisposeWith(cleanup);
        });
    }
}

MainWindowViewModel

   public class MainWindowViewModel : ReactiveObject
{
    private readonly IRandomService m_RandomService;
    public ReactiveCommand<Unit, Unit> RandonListCommand { get; set; }

    public MainWindowViewModel(IRandomService randomService)
    {
        m_RandomService = randomService;

        RandonListCommand = ReactiveCommand.Create(() => { CallRandomService(); });

        randomService.WhenAnyValue(rs => rs.ModelList).WhereNotNull().Subscribe(_ => TriggerUpdateUI());
    }

    private void CallRandomService()
    {
        Debug.WriteLine("Random is called");
        var random = new Random();
        var take = random.Next(1, 4);
        Debug.WriteLine($"Take is {take}");
        m_RandomService.UpdateList(take);
    }

    private void TriggerUpdateUI()
    {
        Debug.WriteLine("List changed");
        foreach (var model in m_RandomService.ModelList)
        {
            Debug.WriteLine($"{model.Id} {model.Name}");
        }
    }
}

RandomService

     public class RandomService : ReactiveObject, IRandomService
{
    private List<RandomModel> _privateList; 
    public RandomService()
    {
        _privateList = new List<RandomModel>
        {
            new RandomModel { Id = 1, Name = "FirstRandom" },
            new RandomModel { Id = 2, Name = "SecondRandom" },
            new RandomModel { Id = 3, Name = "SecondRandom" },
            new RandomModel { Id = 4, Name = "SecondRandom" }
        };
        _modelList = new();
    }
    private ObservableCollection<RandomModel> _modelList;
    public ObservableCollection<RandomModel> ModelList
    {
        get => _modelList;
        set => this.RaiseAndSetIfChanged(ref _modelList, value);
    }

    public void UpdateList(int take)
    {
        _modelList.Clear();
        Debug.WriteLine($"ModelList count {_modelList.Count}");

        var addToUI = _privateList.Take(take).ToList();
        addToUI.Shuffle();

        addToUI.ForEach(p => ModelList.Add(p));
        Debug.WriteLine($"ModelList count {_modelList.Count}");
    }
}

IRandomService

    public interface IRandomService
{
    ObservableCollection<RandomModel> ModelList { get; }

    void UpdateList(int take);
}

From my point of view everything is correct if I read the definiton of ObservableCollection

"Represents a dynamic data collection that provides notifications when items get added or removed, or when the whole list is refreshed."

So my question is, why is my TriggerUpdateUI() never called. ( except at the start of the app when it's initialized).

enter image description here


Solution

  • randomService.WhenAnyValue(rs => rs.ModelList).WhereNotNull().Subscribe(_ => TriggerUpdateUI());

    WhenAnyValue is just watching randomService for property change notifications for ModelList. You haven't set up anything to look for collection related changes.

    From my point of view everything is correct if I read the definiton of ObservableCollection

    "Represents a dynamic data collection that provides notifications when items get added or removed, or when the whole list is refreshed."

    Your quote comes from the MS Docs on ObservableCollection. It is capable of producing collection change notifications, but you still need to setup something to react to them via ReactiveUI / DynamicData.

    ReactiveUI Handbook - Collections