4

I have the following view model class (based on RxUI design guidelines):

public class SomeViewModel : ReactiveObject
{
    private readonly ObservableAsPropertyHelper<int> m_count;

    public ReactiveCommand<object> AddItem { get; set; }

    public int Count
    {
        get { return m_count.Value; }
    }

    public IReactiveList<string> SomeList { get; private set; }

    public SomeViewModel ()
    {
        SomeList = new ReactiveList<string>();

        AddItem = ReactiveCommand.Create();
        AddItem.Subscribe(x => SomeList.Add("new item"));

        m_count = SomeList.CountChanged.ToProperty(this, x => x.Count, 100);

        SomeList.Add("first item");
    }
}

And the following XAML binding:

<Button Command="{Binding AddItem}" Content="{Binding Count}" />

When my view is displayed, the button content is 100 instead of 1. Then when the button is clicked, the content updates to 2, then 3, then 4, etc.

Why is the the first call to SomeList.Add() not observed?

bugged87
  • 3,026
  • 2
  • 26
  • 42

1 Answers1

0

This is a subtle bug. ToProperty is lazy, meaning it won't start Subscribing until the XAML binding is set up (i.e. after the call to SomeList). You should be able to fix this by writing:

 SomeList.CountChanged.StartWith(SomeList.Count).ToProperty(this, x => x.Count, 100);
Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • This fix won't benefit me in my actual use case. The example above was simplified to demonstrate the issue. In reality, my call to `SomeList.Add("first item")` does not occur in the constructor but rather in an AutoMapper mapping. In other words, `SomeViewModel` gets created by AutoMapper, and then AutoMapper detects that `SomeList` has already been initialized in the constructor so it simply calls `SomeList.AddRange()` to populate the list with the mapped values. It's this `AddRange()` call that does not seemed to be observed. – bugged87 Jan 29 '15 at 14:36
  • What I really need to accomplish is to allow my UI to know that the list has been updated so that it can display the correct initial value, not just a default value. I'm only using the `CountChanged` observable because it's convenient for detecting a change in the list (I want to know about items added and removed without having to watch two different observables), but I'm not really concerned with the actual count. – bugged87 Jan 29 '15 at 14:41
  • FYI, your answer above doesn't actually fix the sample code above either. The initial value displayed in the UI for the button content is still 100. – bugged87 Jan 29 '15 at 14:42
  • If I give `Count` a setter that raises it's own property changed event and simply `Subscribe()` to `SomeList.ItemChanged` to set `Count` myself, then everything works as expected. But I was hoping to understand why the recommended approach of using ObservableAsPropertyHelper was not working. – bugged87 Jan 29 '15 at 14:45
  • Same problem here, can't get notifications firing with StartWith().ToProperty(). Any other way than Subscribe()? – ericdes Mar 26 '16 at 19:18