Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: AutoRefresh() on a collection of objects triggers listeners before their own internal OAPH listeners? #3922

Open
seleborg opened this issue Oct 11, 2024 · 0 comments
Labels

Comments

@seleborg
Copy link

Describe the bug 🐞

First off, thanks for all the work on ReactiveUI, it is a very helpful library!

Let's say I have a ViewModel object with two properties, one of which is just a different representation of the other one. I'm using OAPHs to derive the second property's from the first property's value. I set this up in the constructor.

I then create an ObservableCollection<ViewModel> of such objects and want to listen to changes to that collection based on the property. It turns out that that listener gets called before the OAPH's listener, such that I observe an inconsistent state.

I'm very confused by this, I would expect that the OAPH's listener, being set up in the constructor and running on the same thread as the property update, would always run before any external listeners, necessarily set up later. This does not seem to be the case.

A few additional notes:

  • If instead of ToObservableChangeSet().AutoRefresh() I just use vm.WhenAnyValue(x => x.Number), I get the expected result, so it seems to be something with ToObservableChangeSet().AutoRefresh().
  • I'm submitting the minimal example as a unit test, but this behaviour also occurs when running normally, i.e. not in unit tests.

Step to reproduce

Here's a minimal example, written as a unit test (apologies for the non-standard code style, that's just how my editor is set up):

public class ViewModel : ReactiveObject {
    int _number;
    public int Number {
      get => _number;
      set => this.RaiseAndSetIfChanged(ref _number, value);
    }

    ObservableAsPropertyHelper<string> _asString;
    public string AsString => _asString.Value;

    public ViewModel() {
      _number = 0;
      _asString = this.WhenAnyValue(x => x.Number)
        .Select(n => n.ToString())
        .ToProperty(this, nameof(AsString));
    }
  }
  [Fact]
  public static void TestOrdering() {
    ViewModel vm = new();
    bool initializing = true;
    ObservableCollection<ViewModel> vms = new ObservableCollection<ViewModel> { vm };
    _ = vms.ToObservableChangeSet()
      .AutoRefresh(x => x.Number)
      .Subscribe(_ => {
        Debug.WriteLine($"{initializing} vm.Number={vm.Number} vm.AsString={vm.AsString}");
      });
    initializing = false;
    vm.Number = 1;
  }

In this example, ViewModel has a Number property, which can be set, and an AsString property which is supposed to give the string representation of this number. When running this example, I get the following two log lines, the first of which can be ignored:

08:41:13:537	True vm.Number=0 vm.AsString=0
08:41:13:537	False vm.Number=1 vm.AsString=0

As you can see, Number and AsString represent different values, making my ViewModel's state look inconsistent.

Reproduction repository

No response

Expected behavior

I would expect the OAPH to run first, given I'm setting it up first and am not specifying that anything runs in the background, and would expect the following log lines (with Number and AsString showing the same thing):

08:41:13:537	True vm.Number=0 vm.AsString=0
08:41:13:537	False vm.Number=1 vm.AsString=1

Screenshots 🖼️

No response

IDE

Visual Studio 2022

Operating system

Windows

Version

No response

Device

No response

ReactiveUI Version

20.1.63

Additional information ℹ️

No response

@seleborg seleborg added the bug label Oct 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant