Avalonia
Avalonia copied to clipboard
Disable Animations processing when Visual's not visible
This disables the processing of animation values whenever the target visual is not effectively visible.
cc @grokys
You can test this PR using the following package version. 11.1.999-cibuild0045199-beta
. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]
You can test this PR using the following package version. 11.1.999-cibuild0045220-beta
. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]
I'm not sure about this. The control's properties won't be updated at all while it's not visible, which I would find surprising. What if I am reading the output of some animated value of a control, and that control then becomes invisible?
The animated value in this scenario could very reasonably be affecting another still visible control in the same window. It's also possible (though I wouldn't do this) to bind the animated value to a viewmodel property and expect it to be continually updated.
These are edge cases and I think it's reasonable to disable animation of hidden control by default. But I would recommend also adding a way to configure a control to still animate while hidden.
I think this feature is very valuable but I also agree with @TomEdwardsEnscape that if properties are not animated while invisible it may have hard to workaround side effects. e.g. there are transitions (Crossfade, PageSlide, etc. I wonder if these work if these set the visibility to be false). I think the proper implementation would be to disable just the Invalidation. Properties would be updated but changes would not call Invalidate - or an empty Invalidate would not propagate further - or empty dirty rects would not force rendering (swapping buffers, etc.) This may have benefits even outside of the Animations (e.g. user changing a bound value of a hidden label will trigger rendering but will change no pixels - it still uses GPU though for swapping buffers).
Please see this PR if it makes sense https://github.com/AvaloniaUI/Avalonia/pull/14904
Hi folks!
I think it's an edge case that doesn't really makes sense for most applications. For one, nothing should depend directly on animation's output values at all. All animations should be "storyboarded" with keyframes and what not.
Another thing is that IIRC (please correct me if i'm wrong), WPF/UWP also does the same behavior. Having the properties change from the hidden visual's animation will still waste CPU cycles which is what we wanted to fix on this PR in the first place.
If the initial intend is to reduce CPU usage of ProgressBar indeterminate animation, I would suggest just change the control theme, animate it when it is visible. But globally I think animation should still take effect. I used FillMode=Forward a lot in code to animate control positioning in Ursa.Avalonia project. (think about Drawer Sliding in while its width differs each time).
What prevents you from animating opacity instead of visibility?
I was going to say that "WPF also disables animations when a control is hidden" which is what I thought happened, but I went and checked it:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="c"/>
</Window.Resources>
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<CheckBox x:Name="Visible" IsChecked="True">Is Visible</CheckBox>
<TextBlock Margin="8 0 0 0" Text="{Binding Opacity, ElementName=MyRectangle}"/>
</StackPanel>
<Canvas>
<Rectangle Name="MyRectangle"
Width="100"
Height="100"
Fill="Blue"
Visibility="{Binding IsChecked, ElementName=Visible, Converter={StaticResource c}}">
<Rectangle.Triggers>
<!-- Animates the rectangle's opacity. -->
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyRectangle"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</DockPanel>
And it seems that animations run on invisible controls in WPF...
So I'm tempted to agree with the commenters that we probably shouldn't merge this PR, though I think we should also check CSS as our animation system is more like that than WPF.
You can test this PR using the following package version. 11.2.999-cibuild0048311-alpha
. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]
Hi folks, upon discussing with @grokys we have found out the following:
https://github.com/AvaloniaUI/Avalonia/assets/16554748/483c29af-c8e7-46eb-9ae7-a6f23e3bc14c
On WPF at least, the main indication of activity on the ProgressBar's Indeterminate animation seems to stop and reset when the visibility changes
Other findings:
WPF:
Multiple Indeterminate ProgressBars clocking at around 11% cpu usage
Total silence once the Parent Visibility is set to Collapsed and/or Hidden.
@TomEdwardsEnscape was about to post as well, thanks!
We just found it out now
Another finding:
https://github.com/AvaloniaUI/Avalonia/assets/16554748/918cdcbf-7e9f-4e5e-b346-1a6ffb73d579
CSS does stop animations on hide.
I think the problem is not that the animation is running (that's fairly cheap to recalculate some numbers, although can be optimized in specific cases, e.g. ProgressBar). The problem is that changing a property of invisible control triggers invalidation + redraw. I still believe the best solution would be to improve this part - if the control is invisible then don't add its dirty rect and thus don't force redrawing. I tried it here https://github.com/AvaloniaUI/Avalonia/pull/14904 but it does not cover the case when the control was visible and then goes invisible.
Try this. Enable showing dirty rects. Create a hidden indeterminate ProgressBar. Its dirty rect is still visible and applied to the position where the ProgressBar was before. So it is redrawing some random position over and over with no visual result.