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.17k stars 2.18k forks source link

Binding two controls to one objects causes infinite loop #7760

Closed CollinAlpert closed 2 years ago

CollinAlpert commented 2 years ago

Describe the bug When binding two controls two one object (e.g. to have one SelectedItem for two ListBoxes), updating the value causes an infinite loop.

To Reproduce ViewModel:

public class MainWindowViewModel : ViewModelBase
{
    private MyModel _selectedModel;

    private IEnumerable<MyModel> Items { get; } = new[]
    {
        new MyModel(1, "First entry"),
        new MyModel(2, "Second entry"),
        new MyModel(3, "Third entry"),
        new MyModel(4, "Fourth entry"),
    };

    public MyModel SelectedModel
    {
        get => _selectedModel;
        set => this.RaiseAndSetIfChanged(ref _selectedModel, value);
    }
}

public record MyModel(int Id, string Name);

View:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:AvaloniaRepro.ViewModels"
        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="AvaloniaRepro.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="AvaloniaRepro">

    <Design.DataContext>
        <vm:MainWindowViewModel/>
    </Design.DataContext>

    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <StackPanel.Styles>
                <Style Selector="ListBox">
                    <Setter Property="ItemTemplate">
                        <DataTemplate DataType="{x:Type vm:MyModel}">
                            <TextBlock Text="{Binding Name}" />
                        </DataTemplate>
                    </Setter>
                </Style>
            </StackPanel.Styles>
            <ListBox Items="{Binding Items}"
                     SelectedItem="{Binding SelectedModel, Mode=OneWayToSource}"/>
            <Separator Width="1" Background="Black" />
            <ListBox Items="{Binding Items}"
                     SelectedItem="{Binding SelectedModel, Mode=OneWayToSource}"/>
        </StackPanel>
        <TextBlock Text="{Binding SelectedModel.Name, Mode=OneWay, FallbackValue='-'}" />
    </StackPanel>

</Window>

Click on any of the ListBoxItems to trigger the infinite loop.

Expected behavior The selected value of the ListBox is displayed in the TextBlock.

Desktop (please complete the following information):

Additional context May be related to #4438

When removing Mode=OneWayToSource from one of the controls, it works, however then the lists are synchronized.

When implementing the INotifyPropertyChanged pattern myself, the problem still occurs which suggests ReactiveUI is not the problem.

guilhermeolisi commented 2 years ago

Hi, found the same problem using Mode=OneWayToSource, when i switch to Mode=TwoWay, the problem no longer happens.

Windows 10 Avalonia 0.10.13

maxkatz6 commented 2 years ago

Duplicate of https://github.com/AvaloniaUI/Avalonia/issues/4438