System.StackOverflowException when using OneWayToSource binding
LtDetFrankDrebin opened this issue · 13 comments
When I use OneWayToSource binding from a control to ViewModel I get wrong behavior:
- StackOverflowException happens.
- In spite of OneWayToSource binding control tries to read from Property in ViewModel.
Example 1:
View:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Tests.ViewModels;assembly=Tests"
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="Tests.Views.MainWindowView"
Icon="/Assets/avalonia-logo.ico"
Title="Tests">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<ItemsControl Items="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Bounds="{Binding Bounds, Mode=OneWayToSource}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
ViewModel:
using Avalonia;
using ReactiveUI;
using System.Collections.Generic;
namespace Tests.ViewModels
{
public class MainWindowViewModel : ReactiveObject
{
public class Item : ReactiveObject
{
Rect _bounds;
public Rect Bounds
{
get => _bounds;
set => this.RaiseAndSetIfChanged( ref _bounds, value );
}
}
List<Item> _items = new List<Item> { new Item(), new Item(), };
public List<Item> Items
{
get => _items;
set => this.RaiseAndSetIfChanged( ref _items, value );
}
}
}
Result:
After executing I get infinity loop in set => this.RaiseAndSetIfChanged( ref _bounds, value );
.
Example 2:
View:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Tests.ViewModels;assembly=Tests"
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="Tests.Views.MainWindowView"
Icon="/Assets/avalonia-logo.ico"
Title="Tests">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Grid RowDefinitions="* *" ColumnDefinitions="* *" ShowGridLines="True">
<TextBlock Grid.Row="0" Grid.Column="0" Width="100" Height="100" Background="Red"
IsPointerOver="{Binding IsActive, Mode=OneWayToSource}" Text="{Binding IsActive, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="1" Width="100" Height="100" Background="Blue"
IsPointerOver="{Binding IsActive, Mode=OneWayToSource}" Text="{Binding IsActive, Mode=OneWay}" />
</Grid>
</Window>
ViewModel:
using ReactiveUI;
namespace Tests.ViewModels
{
public class MainWindowViewModel : ReactiveObject
{
bool _isActive;
public bool IsActive
{
get => _isActive;
set => this.RaiseAndSetIfChanged( ref _isActive, value );
}
}
}
Result:
After executing and moving mouse over red or blue square I get infinity loop in set => this.RaiseAndSetIfChanged( ref _isActive, value );
.
I'm using <PackageReference Include="Avalonia" Version="0.9.11" />
.
@LtDetFrankDrebin could you fix your markdown? I'm having trouble reading it.
Thanks to the one who fixed markdown for me. I used "Insert code" button <>
from tool panel and it added only single ` quotes, but with them "<Window" tags are invisible. Now I know that triple ``` quotes needed for code.
As a workaround I use MultiValueConverter now:
View:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Tests.ViewModels;assembly=Tests"
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="Tests.Views.MainWindowView"
Icon="/Assets/avalonia-logo.ico"
Title="Tests">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<Window.Resources>
<vm:MultiValueConverter x:Key="MultiValueConverter" />
</Window.Resources>
<Grid RowDefinitions="* *" ColumnDefinitions="* *" ShowGridLines="True">
<TextBlock Grid.Row="0" Grid.Column="0" Width="100" Height="100" Background="Red" Text="{Binding IsActive, Mode=OneWay}">
<TextBlock.Tag>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="DataContext" />
<Binding RelativeSource="{RelativeSource Self}" Path="IsPointerOver" />
</MultiBinding>
</TextBlock.Tag>
</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Width="100" Height="100" Background="Blue" Text="{Binding IsActive, Mode=OneWay}">
<TextBlock.Tag>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="DataContext" />
<Binding RelativeSource="{RelativeSource Self}" Path="IsPointerOver" />
</MultiBinding>
</TextBlock.Tag>
</TextBlock>
</Grid>
</Window>
ViewModel:
using Avalonia;
using Avalonia.Data.Converters;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Tests.ViewModels
{
public class MainWindowViewModel : ReactiveObject
{
bool _isActive;
public bool IsActive
{
get => _isActive;
set => this.RaiseAndSetIfChanged( ref _isActive, value );
}
}
public class MultiValueConverter : IMultiValueConverter
{
public object Convert( IList<object> values, Type targetType, object parameter, CultureInfo culture )
{
if ( !(values[ 0 ] is MainWindowViewModel vm) )
return AvaloniaProperty.UnsetValue;
if ( !(values[ 1 ] is bool isPointerOver) )
return AvaloniaProperty.UnsetValue;
return vm.IsActive = isPointerOver;
}
}
}
I am running into this issue as well. Having two OneWayToSource binding binding to the same object result in an infinite loop when calling this.RaiseAndSetIfChanged( ref _value, value );
This also happens when binding DatePicker. Seems like the "Date" and "SelectedDate" are both trying to update.
@grokys Any updates on this issue? I have to remove most of the OneWayToSourceBinding to avoid the StackOverFlow error.
Was not fixed in 11.0.7
That's expected as the PR was not released yet. It's only testable in nightly builds. https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
Was not fixed in 11.0.7
That's expected as the PR was not released yet. It's only testable in nightly builds. https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
I'm sorry that I saw that the PR had been merged and subconsciously thought it was already in the release version
But in 11.1.999-cibuild0043857-beta also not fix
I find a case that constantly triggering this issue. Binding a nullable control property to a non-nullable vm property with OneWayToSource will trigger this StackOverflow.
nvm, tested new nightly, the behavior changed.