File: PerfMargin\StatusIndicator.xaml.cs
Web Access
Project: src\src\VisualStudio\VisualStudioDiagnosticsToolWindow\Roslyn.VisualStudio.DiagnosticsWindow.csproj (Roslyn.VisualStudio.DiagnosticsWindow)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
 
namespace Roslyn.Hosting.Diagnostics.PerfMargin
{
    /// <summary>
    /// Interaction logic for StatusIndicator.xaml
    /// </summary>
    public partial class StatusIndicator : UserControl
    {
        private readonly ActivityLevel _activityLevel;
        private bool _changedSinceLastUpdate;
 
        internal StatusIndicator(ActivityLevel activityLevel)
        {
            InitializeComponent();
 
            _activityLevel = activityLevel;
            _changedSinceLastUpdate = activityLevel.IsActive;
        }
 
        // Don't use WPF one way binding since it allocates too much memory for this high-frequency event
        internal void Subscribe()
        {
            _activityLevel.IsActiveChanged += this.ActivityLevel_IsActiveChanged;
        }
 
        internal void Unsubscribe()
        {
            _activityLevel.IsActiveChanged -= this.ActivityLevel_IsActiveChanged;
        }
 
        private void ActivityLevel_IsActiveChanged(object sender, EventArgs e)
        {
            _changedSinceLastUpdate = true;
        }
 
        private const double MinimumScale = 0.2;
        private static readonly DoubleAnimation s_growAnimation = new DoubleAnimation(1.0, new Duration(TimeSpan.FromSeconds(1.0)), FillBehavior.HoldEnd);
        private static readonly DoubleAnimation s_shrinkAnimation = new DoubleAnimation(0.0, new Duration(TimeSpan.FromSeconds(0.33333)), FillBehavior.HoldEnd);
 
        public void UpdateOnUIThread()
        {
            if (!_changedSinceLastUpdate)
            {
                return;
            }
 
            _changedSinceLastUpdate = false;
 
            // Remove existing animation
            this.clipScale.BeginAnimation(ScaleTransform.ScaleXProperty, null);
 
            // For very short durations, the growth animation hasn't even begun yet, so make
            // sure something is visible.
            this.clipScale.ScaleX = Math.Max(this.clipScale.ScaleX, MinimumScale);
 
            var anim = _activityLevel.IsActive ? s_growAnimation : s_shrinkAnimation;
            this.clipScale.BeginAnimation(ScaleTransform.ScaleXProperty, anim, HandoffBehavior.SnapshotAndReplace);
        }
    }
}