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] ReactiveComponentBase doesn't update properties when ViewModel is set/changed #2298

Closed
limefrogyank opened this issue Jan 4, 2020 · 2 comments · Fixed by #2303
Closed

Comments

@limefrogyank
Copy link
Contributor

limefrogyank commented Jan 4, 2020

Describe the bug
If you first create your view implementing ReactiveComponentBase<SomeViewModel> and then later set the ViewModel property to an instance of SomeViewModel, the page does not update with the contents of the viewmodel. The page will only update when you manually call StateHasChanged().

Related to the end of #2240

Steps To Reproduce

  1. Create a ReactiveComponentBase<> view with the ViewModel property set to null.
  2. Set some properties in the view with the null-conditional operator. Text=@(ViewModel?.SampleText)
  3. Create a button that creates a ViewModel and sets it to the view's ViewModel property.
  4. Run, then hit the button: None of the properties will show on the screen.

Expected behavior
As soon as the ViewModel is set, the page should update to show the new contents.

Additional context
https://github.com/reactiveui/ReactiveUI/blob/master/src/ReactiveUI.Blazor/ReactiveComponentBase.cs#L40-L52

The problem is here:

 var propertyChangedObservable = this.WhenAnyValue(x => x.ViewModel)
                .Select(x => Observable.FromEvent<PropertyChangedEventHandler, Unit>(
                    eventHandler =>
                    {
                        void Handler(object sender, PropertyChangedEventArgs e) => eventHandler(Unit.Default);

                        return Handler;
                    },
                    eh => x.PropertyChanged += eh,
                    eh => x.PropertyChanged -= eh))
                .Switch();

            propertyChangedObservable.Do(_ => StateHasChanged()).Subscribe();

and here:

public T ViewModel
        {
            get => _viewModel;
            set
            {
                if (EqualityComparer<T>.Default.Equals(_viewModel, value))
                {
                    return;
                }

                _viewModel = value;
                OnPropertyChanged();
            }
        }

When the ViewModel setter is run, the OnPropertyChanged is triggering both WhenAnyValue observable and the inner event-observable. Somehow, the Switch() statement is being triggered first... and the inner event-observable is being triggered on the old observable for ViewModel, rather than the new observable for the new ViewModel.
http://reactivex.io/documentation/operators/switch.html
Apparently, those old events just go nowhere... so they are not triggering the Do() statement.

A fix would be to stick a StateHasChanged() into the ViewModel's setter after the OnPropertyChanged call.

@open-collective-bot
Copy link

open-collective-bot bot commented Jan 4, 2020

Hey @limefrogyank 👋,

Thank you for opening an issue. We will get back to you as soon as we can. Also, check out our Open Collective and consider contributing financially.

https://opencollective.com/reactiveui

PS.: We offer priority support for all financial contributors. Don't forget to add priority label once you start contributing 😄

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms!

@glennawatson
Copy link
Contributor

The solution is almost there. Just needs a WhenAnyValue() also for the ViewModel itself, since at the moment it's only detecting properties changing on the ViewModels. I will implement a fix later today. Thanks for the report.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants