0
votes

This ReactiveUserControl is inside a ListBoxItem. The ListBox is using virtualization. If I register the ShowDialogAsync on WhenActivated (*1) only the firsts UserControls are bound because virtualization recycles controls. Then, I should to bind using OnDataContextEndUpdate (*2). But this is not veri "reactive" way.

public class CentreRowUserCtrl : ReactiveUserControl<CentreRowViewModel>
{
    public CentreRowUserCtrl()
    {
        InitializeComponent();
        // (*1):
        // this.WhenActivated(d =>  
        //      d(ViewModel!.ShowDialog.RegisterHandler(ShowDialogAsync)));
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);            
    }

    protected override void OnDataContextEndUpdate()
    {
        base.OnDataContextBeginUpdate();
        // (*2):
        ViewModel?.ShowDialog.RegisterHandler(ShowDialogAsync);            
    }

How can I register with ReactiveUI in a virtualization context?

1
Are you saying that the control is only activated once? Please provide a repo that demostrates your issue. A virtualized control should still get loaded/activated. - mm8
@nm8: I also posted the issue on Avalonia discussions: github.com/AvaloniaUI/Avalonia/discussions/6427 - dani herrera

1 Answers

0
votes

Answered here: https://github.com/AvaloniaUI/Avalonia/discussions/6427#discussioncomment-1191558

As stated in WhenActivated documentation, the WhenActivated ReactiveUI feature is a way to track disposables. There is no guarantee that the ViewModel property (the DataContext property of an IViewFor) won't be null when the control is activated, and that the view model won't change since control activation. That's why the IViewFor.ViewModel property is marked as nullable in ReactiveUI. The general recommendation is to never access the ViewModel property directly inside a WhenActivated block. Always use a call to WhenAnyValue in a similar fashion to this code snippet:

this.WhenActivated(disposables => {
    this.WhenAnyValue(x => x.ViewModel)
        .Subscribe(vm => { /* Here you can access the view model safely. */ })
        .DisposeWith(disposables);
});