question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

The initialisation sequence of XAML bindings and WhenActivated has changed

See original GitHub issue

Using build 0.8.999-cibuild0003548-beta. The creation of the view’s XAML bindings now occurs before the WhenActivated call in the view model. In v0.8.1, WhenActivated was called before the XAML bindings were made.

The original sequence feels correct to me as you can use the WhenActivated call to setup view model properties that can then be bound in XAML without implementing INotifyPropertyChanged. This is how DynamicData (ReactiveUI for collections) with ReadOnlyObservableCollection works, requiring no INotifyPropertyChanged code.

This sequence change causes failure to display the items generated using DynamicData Bind when called from WhenActivated. This previously worked in v0.8.1. Here is an example of a view / view model that worked in v0.8.1 but now creates the ListBox bound to null instead of the generated list:

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="AvaloniaApplication8.Views.MyView">
  <StackPanel>
    <TextBlock Text="Here is my list of 3 items:" />
    <ListBox Items="{Binding Items}"/>
  </StackPanel>
</UserControl>

    public class MyViewModel : ReactiveObject, IRoutableViewModel, ISupportsActivation
    {
        public string UrlPathSegment => "MyView";

        public IScreen HostScreen { get; set; }

        public ViewModelActivator Activator { get; } = new ViewModelActivator();
        private ReadOnlyObservableCollection<string> _items;
        public ReadOnlyObservableCollection<string> Items => _items;

        public MyViewModel(IScreen screen, MyModel model)
        {
            HostScreen = screen;

            this.WhenActivated(disposables =>
            {
                model.Values.ToObservableChangeSet()
                    .ObserveOn(RxApp.MainThreadScheduler)
                    .Bind(out _items)
                    .Subscribe()
                    .DisposeWith(disposables);

                //this.RaisePropertyChanged(nameof(Items));
            });
        }
    }

Here is the full repo example. App8.zip

Adding the this.RaisePropertyChanged(nameof(Items)); line fixes the problem in build 0.8.999-cibuild0003548-beta.

So my question is whether : a) the initialisation sequence behaviour is undefined and I should not rely on the initialisation sequence being in any particular order? or b) is this a breaking change? or c) is it a bug?

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:8 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
aguahombrecommented, Aug 15, 2019

The workaround using RaisePropertyChanged gets quite messy when you want to bind an initial SelectedItem to the ItemsControl.

<ListBox Items="{Binding Items}" SelectedItem="{Binding MySelection}"/>

As the Items binding returns null when the SelectedItem binding is made, the ItemsControl sets the SelectedItem back to null as it doesn’t match any item in the Items.

When WhenActivated is called and the Items gets updated by RaisePropertyChanged, the SelectedItem is now null and the ItemsControl selects the first item in the Items. This is not the required behaviour.

My current workaround involves saving the current selection and restoring it after RaisePropertyChanged

                var selected = MySelection;
                this.RaisePropertyChanged(nameof(Items));
                MySelection= selected ;

I suspect this will not be the only messy side affect of this change.

1reaction
worldbeatercommented, Aug 14, 2019

We use AttachedToVisualTree and DetachedFromVisualTree events for IVisuals and Opened and Closed events for Windows to handle activation and deactivation, and that shouldn’t have changed since 0.8.1 https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs#L61 So looks like the behaviour of visual tree events changed recently.

Worth investigating how activation works on WPF etc. but generally a call to RaisePropertyChanged looks reasonable, while on most platforms activation happens after view model initialization, and the _items property is left unassigned when the initialization completes

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use WhenActivated with properties in avalonia
Option #1. The most obvious pattern that allows you to resolve the issue is to use the null coalescing operator. By using this...
Read more >
A Compelling Example
The ReactiveUI binding has a few advantages over the XAML based binding. The first advantage is that property name changes will generate a...
Read more >
UserControl Class - Typedescriptor
Provides the base class for defining a new control that encapsulates ... The initialisation sequence of XAML bindings and WhenActivated has changed #2845....
Read more >
Binding declarations overview - WPF .NET
Learn how to declare a data binding in XAML or code for your application development in Windows Presentation Foundation (WPF).
Read more >
Build Cross-Platform Reactive .NET Apps - Artyom V. Gorchakov
In order to have the bindings working, we create a new form, implement the IViewFor interface, and place the binding extension methods into...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found