dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.11k stars 1.17k forks source link

WPF ProgressBars with IsIndeterminate = true appear to leak animations, since .NET 4.5 #6264

Closed ryanmolden closed 2 years ago

ryanmolden commented 2 years ago

Problem description: WPF's ProgressBar uses a well-known named template part (GlowingRectTemplateName which is == PART_GlowRect) in order to control the indeterminate animation. Specifically it wants to stop the animation when the control becomes invisible.

Since aero2.normalcolor.xaml was introduced this no longer works as the template has no PART_GlowRect and instead triggers the animation based on the Indeterminate VisualState.

Specifically see

Code here: https://github.com/dotnet/wpf/blob/89d172db0b7a192de720c6cfba5e28a1e7d46123/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ProgressBar.cs#L62

and here: https://github.com/dotnet/wpf/blob/89d172db0b7a192de720c6cfba5e28a1e7d46123/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ProgressBar.cs#L220

and template here (other templates have similar issues, other than aero.normalcolor.xaml): https://github.com/dotnet/wpf/blob/89d172db0b7a192de720c6cfba5e28a1e7d46123/src/Microsoft.DotNet.Wpf/src/Themes/PresentationFramework.Aero2/Themes/Aero2.NormalColor.xaml#L4428

This means that for stock WPF ProgressBars with IsIndeterminate=True, the animations will run forever regardless of whether the animation is visible. This is esepcially bad on high-refresh rate monitors as the callbacks occur much more frequently and keep what could be an idle system non-idle preventing battery saving mode switches on laptops.

Actual behavior: Animations run forever

Expected behavior: Animations stop when the control becomes invisible, as the code appears to facilitate.

Minimal repro:

MainWindow.xaml

<Window x:Class="AnimationTestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AnimationTestApp"
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
  <Grid Name="HostGrid">
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid Grid.Column="0" Name="HostElement_Collapsed" Margin="10" VerticalAlignment="Stretch">
      <ProgressBar Width="100" Height="50" IsIndeterminate="True" VerticalAlignment="Center" HorizontalAlignment="Center"/>
    </Grid>
  </Grid>
</Window>

MainWindow.xaml.cs

using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace AnimationTestApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Task.Delay(2000).ContinueWith((t) =>
                {
                    return Dispatcher.InvokeAsync(() =>
                        {
                            Grid panel = (Grid)this.FindName("HostElement_Collapsed");
                            if (panel != null)
                                panel.Visibility = Visibility.Collapsed;
                        }).Task;
                });
        }
    }
}

Placing a breakpoint on System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames.GetCurrentValueCore with a 'when hit' action that simply say prints a line to the debugger shows that even when the animation is invisible the callbacks continue.

Changing the markup such that IsIndeterminate is bound to IsVisible and rerunning the repro with the same printing breakpoint shows then the animations stop as the control becomes invisible (as the VisualState = Indeterminate becomes no longer true)

ThomasGoulet73 commented 2 years ago

@ryanmolden I opened #6266 which should fix this issue. Thank you for the detailed repro, it was very helpful!