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

IsCheckedChanged fires before PropertyChanged #18053

Open
ALDamico opened this issue Jan 25, 2025 · 5 comments
Open

IsCheckedChanged fires before PropertyChanged #18053

ALDamico opened this issue Jan 25, 2025 · 5 comments
Labels

Comments

@ALDamico
Copy link

Describe the bug

ToggleButton's IsCheckedChanged event fires before PropertyChanged. This has the side effect of causing commands that fire on this event to use the incorrect boolean value.

To Reproduce

This repository contains a minimal example of this behavior

https://github.com/ALDamico/IsCheckedChangedBug

Expected behavior

I'd expect the IsCheckedChanged event to fire after PropertyChanged fires.

Avalonia version

11.2.3

OS

Windows

Additional context

Possible workaround

Trigger the command on PropertyChanged, if the ViewModel has few properties.

@ALDamico ALDamico added the bug label Jan 25, 2025
@robloo
Copy link
Contributor

robloo commented Jan 27, 2025

I don't think this is possible without something being wrong at a deeper level.

OnIsCheckedChanged(new RoutedEventArgs(IsCheckedChangedEvent));

IsCheckedChanged is fired FROM the property changed notification itself. The base OnPropertyChanged is called first as well.

In fact, within an event handler, it's designed to be able to read the current IsChecked property value.

@zii-dmg
Copy link
Contributor

zii-dmg commented Jan 27, 2025

Tried in simple repro without tasks etc.

Something with animation?

Difference after Avalonia.Base.dll!Avalonia.AvaloniaObject.RaisePropertyChanged<bool?>(Avalonia.AvaloniaProperty<bool?> property, Avalonia.Data.Optional<bool?> oldValue, Avalonia.Data.BindingValue<bool?> newValue, Avalonia.Data.BindingPriority priority, bool isEffectiveValue).

First breakpoint IsCheckedChanged stacktrace:

AvaTest.dll!AvaTest.MainWindow.Btn_IsCheckedChanged(object sender, Avalonia.Interactivity.RoutedEventArgs e) Line 25	C#
Avalonia.Base.dll!Avalonia.Interactivity.Interactive.AddHandler.__InvokeAdapter|4_0<Avalonia.Interactivity.RoutedEventArgs>(System.Delegate baseHandler, object sender, Avalonia.Interactivity.RoutedEventArgs args)
Avalonia.Base.dll!Avalonia.Interactivity.Interactive.AddHandler.AnonymousMethod__4_1(System.Delegate baseHandler, object sender, Avalonia.Interactivity.RoutedEventArgs args)
Avalonia.Base.dll!Avalonia.Interactivity.EventRoute.RaiseEventImpl(Avalonia.Interactivity.RoutedEventArgs e)
Avalonia.Base.dll!Avalonia.Interactivity.Interactive.RaiseEvent(Avalonia.Interactivity.RoutedEventArgs e)
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.OnIsCheckedChanged(Avalonia.Interactivity.RoutedEventArgs e)
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.OnPropertyChanged(Avalonia.AvaloniaPropertyChangedEventArgs change)
Avalonia.Base.dll!Avalonia.AvaloniaObject.OnPropertyChangedCore(Avalonia.AvaloniaPropertyChangedEventArgs change)
Avalonia.Base.dll!Avalonia.Animation.Animatable.OnPropertyChangedCore(Avalonia.AvaloniaPropertyChangedEventArgs change)
Avalonia.Base.dll!Avalonia.AvaloniaObject.RaisePropertyChanged<bool?>(Avalonia.AvaloniaProperty<bool?> property, Avalonia.Data.Optional<bool?> oldValue, Avalonia.Data.BindingValue<bool?> newValue, Avalonia.Data.BindingPriority priority, bool isEffectiveValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.NotifyValueChanged(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? oldValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.SetAndRaiseCore(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? value, Avalonia.Data.BindingPriority priority, bool isOverriddenCurrentValue, bool isCoercedDefaultValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.SetCurrentValueAndRaise(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Base.dll!Avalonia.PropertyStore.ValueStore.SetCurrentValue<bool?>(Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Base.dll!Avalonia.AvaloniaObject.SetCurrentValue<bool?>(Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.Toggle()
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.OnClick()

Second got PropertyChanged:

AvaTest.dll!AvaTest.MainWindow.Btn_PropertyChanged(object sender, Avalonia.AvaloniaPropertyChangedEventArgs e) Line 20	C#
Avalonia.Base.dll!Avalonia.AvaloniaObject.RaisePropertyChanged<bool?>(Avalonia.AvaloniaProperty<bool?> property, Avalonia.Data.Optional<bool?> oldValue, Avalonia.Data.BindingValue<bool?> newValue, Avalonia.Data.BindingPriority priority, bool isEffectiveValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.NotifyValueChanged(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? oldValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.SetAndRaiseCore(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? value, Avalonia.Data.BindingPriority priority, bool isOverriddenCurrentValue, bool isCoercedDefaultValue)
Avalonia.Base.dll!Avalonia.PropertyStore.EffectiveValue<bool?>.SetCurrentValueAndRaise(Avalonia.PropertyStore.ValueStore owner, Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Base.dll!Avalonia.PropertyStore.ValueStore.SetCurrentValue<bool?>(Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Base.dll!Avalonia.AvaloniaObject.SetCurrentValue<bool?>(Avalonia.StyledProperty<bool?> property, bool? value)
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.Toggle()
Avalonia.Controls.dll!Avalonia.Controls.Primitives.ToggleButton.OnClick()

@robloo
Copy link
Contributor

robloo commented Jan 27, 2025

Or scheduling of the property change notification. Maybe the event is scheduled to fire after the internal override is called.

I know there is change notification grouping, etc. for performance.

The easiest would be simply to schedule OnIsCheckedChanged on the dispatcher too. But I think this is a general issue that should be addressed deeper in the framework.

@timunie
Copy link
Contributor

timunie commented Jan 27, 2025

Also DevTools could give a hint, see Events tab

@ALDamico
Copy link
Author

Also DevTools could give a hint, see Events tab

I'm not terribly familiar with the devtools. What should I be looking out for, specifically?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants