Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.StackOverflowException when using OneWayToSource binding #4438

Closed
LtDetFrankDrebin opened this issue Aug 4, 2020 · 13 comments
Closed
Assignees
Milestone

Comments

@LtDetFrankDrebin
Copy link

LtDetFrankDrebin commented Aug 4, 2020

When I use OneWayToSource binding from a control to ViewModel I get wrong behavior:

  1. StackOverflowException happens.
  2. 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 );.

@LtDetFrankDrebin
Copy link
Author

I'm using <PackageReference Include="Avalonia" Version="0.9.11" />.

@grokys
Copy link
Member

grokys commented Aug 6, 2020

@LtDetFrankDrebin could you fix your markdown? I'm having trouble reading it.

@LtDetFrankDrebin
Copy link
Author

LtDetFrankDrebin commented Aug 7, 2020

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.

@LtDetFrankDrebin
Copy link
Author

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;
		}
	}
}

@CollinAlpert
Copy link
Contributor

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 );

@d3jv
Copy link

d3jv commented May 15, 2023

This also happens when binding DatePicker. Seems like the "Date" and "SelectedDate" are both trying to update.

@laolarou726
Copy link
Contributor

@grokys Any updates on this issue? I have to remove most of the OneWayToSourceBinding to avoid the StackOverFlow error.

@maxkatz6 maxkatz6 added this to the 11.x milestone Jun 3, 2023
@timunie
Copy link
Contributor

timunie commented Dec 25, 2023

Anyone fancy to test if #13970 would solve this issue?

@MakesYT
Copy link
Contributor

MakesYT commented Feb 3, 2024

Anyone fancy to test if #13970 would solve this issue?

Was not fixed in 11.0.7

@timunie
Copy link
Contributor

timunie commented Feb 5, 2024

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

@MakesYT
Copy link
Contributor

MakesYT commented Feb 5, 2024

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

@rabbitism
Copy link
Contributor

rabbitism commented Apr 13, 2024

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.

@grokys
Copy link
Member

grokys commented Jul 3, 2024

Just tried this on latest master and it seems to be fixed. I think it will have been fixed by #13970.

@grokys grokys closed this as completed Jul 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants