AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.35k stars 2.2k forks source link

TabControl: Null DataContext binding values being pushed when switching tabs #10846

Open aldelaro5 opened 1 year ago

aldelaro5 commented 1 year ago

Describe the bug Say we have a MainWindow with a TabControl containing 2 TabItems. Each TabItem's content is a view where the DataContext is bound to a viewModel that the MainWindow's viewModel contain. Everytime the tab is changed, an error gets logged to trace like the following:

[Binding]Error in binding to 'Sandbox.FirstView'.'DataContext': 'Null value in expression '{empty}' at ''.'(FirstView #33726620)

To Reproduce In the Sandbox project, prepare the following:

namespace Sandbox;

public class MainWindowViewModel : INotifyPropertyChanged { private FirstViewModel _firstVm; private SecondViewModel _secondVm;

public FirstViewModel FirstVm
{
    get => _firstVm;
    set
    {
        _firstVm = value;
        OnPropertyChanged();
    }
}

public SecondViewModel SecondVm
{
    get => _secondVm;
    set
    {
        _secondVm = value;
        OnPropertyChanged();
    }
}

public MainWindowViewModel()
{
    _firstVm = new FirstViewModel();
    _secondVm = new SecondViewModel();
}

public event PropertyChangedEventHandler? PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

}


Finally, create the FirstView and SecondView as blank UserControl and their viewModel as blank classes. They don't need to contain anything, just be present.

Once you have everything setup, build the project, run it and then switch tabs. You should see one binding error everytime the current tab changes.

**Expected behavior**
To not see binding errors when switching tabs.

**Desktop (please complete the following information):**

- OS: Arch Linux `6.2.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Mon, 13 Mar 2023 17:02:08 +0000 x86_64 GNU/Linux`
- Version Current master branch, but I also tested preview5 with the same issue

**Additional context**
Interestingly, I was in the idea this issue was related to https://github.com/AvaloniaUI/Avalonia/issues/9438 because I was experiencing this issue and the one I am reporting at the same time and they felt similar, but I have yet to investigate either deeply. It's possible to adapt the project such that both issues are reproduced at the same time though.
aldelaro5 commented 1 year ago

Ok so I investigated this thoroughly, but this one seems out of my league and I would recommend @grokys to check since they worked on value store 3 #8600 which may or may not be involved, let me explain.

This issue seems to have first been observed after value store 3, but not necessarily reproducible since. See, when I bisected this (I didn't used to see this message before), I came across this commit from value store 3: https://github.com/AvaloniaUI/Avalonia/pull/8600/commits/88d59a4ed5b6a8943f1fc06803850f287d64ff67

Which isn't very helpful: it just means we never COULD see the message before.

But in debugging this, what I found is that the reasoning behind isn't too illogical: the visual parent of the old view gets nulled from the tab switch which causes its binding to push null.

The issue is I am confused on 2 potential, different problems:

I can't figure out which one is wrong because I don't know enough about how bindings and value store v3 SHOULD work. I'm just presenting what I seen, but the point is this issue could have potentially been present way before preview 4 even and we might not have been able to observe it.

....or it just wasn't in general there because value store 3 wasn't a thing yet. It gets confusing so hopefully someone can clarify what's happening.