XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace XFEToolBox.WpfCore.Controls
{
    /// <summary>
    /// ModernProgressBar.xaml 的交互逻辑
    /// </summary>
    public partial class ModernProgressBar : UserControl
    {
        public event EventHandler<double>? ProgressChanged;

        #region DependencyProperty
        public CornerRadius ProgressBarCornerRadius
        {
            get { return (CornerRadius)GetValue(ProgressBarCornerRadiusProperty); }
            set { SetValue(ProgressBarCornerRadiusProperty, value); }
        }
        public static readonly DependencyProperty ProgressBarCornerRadiusProperty = DependencyProperty.Register("ProgressBarCornerRadius", typeof(CornerRadius), typeof(ModernProgressBar), new PropertyMetadata(new CornerRadius(10)));

        public bool IsBusy
        {
            get { return (bool)GetValue(IsBusyProperty); }
            set
            {
                SetValue(IsBusyProperty, value);
                SetBusy();
            }
        }
        public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy", typeof(bool), typeof(ModernProgressBar), new PropertyMetadata(false));

        public bool IsError
        {
            get { return (bool)GetValue(IsErrorProperty); }
            set
            {
                SetValue(IsErrorProperty, value);
                SetError();
            }
        }
        public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register("IsError", typeof(bool), typeof(ModernProgressBar), new PropertyMetadata(false));

        public bool IsPause
        {
            get { return (bool)GetValue(IsPauseProperty); }
            set
            {
                SetValue(IsPauseProperty, value);
                SetPause();
            }
        }
        public static readonly DependencyProperty IsPauseProperty = DependencyProperty.Register("IsPause", typeof(bool), typeof(ModernProgressBar), new PropertyMetadata(false));

        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set
            {
                SetValue(MaxValueProperty, value);
                SetTopWidth();
            }
        }
        public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(ModernProgressBar), new PropertyMetadata(100d));

        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set
            {
                SetValue(MinValueProperty, value);
                SetTopWidth();
            }
        }
        public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(ModernProgressBar), new PropertyMetadata(0d));

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set
            {
                SetValue(ValueProperty, value);
                ProgressChanged?.Invoke(this, value);
                SetTopWidth();
            }
        }
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(ModernProgressBar), new PropertyMetadata(0d));

        public Brush ProgressColor
        {
            get { return (Brush)GetValue(ProgressColorProperty); }
            set { SetValue(ProgressColorProperty, value); }
        }
        public static readonly DependencyProperty ProgressColorProperty = DependencyProperty.Register("ProgressColor", typeof(Brush), typeof(ModernProgressBar), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(152, 152, 231))));

        public Brush ProgressErrorColor
        {
            get { return (Brush)GetValue(ProgressErrorColorProperty); }
            set { SetValue(ProgressErrorColorProperty, value); }
        }
        public static readonly DependencyProperty ProgressErrorColorProperty = DependencyProperty.Register("ProgressErrorColor", typeof(Brush), typeof(ModernProgressBar), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(255, 72, 72))));

        public Brush ProgressPauseColor
        {
            get { return (Brush)GetValue(ProgressPauseColorProperty); }
            set { SetValue(ProgressPauseColorProperty, value); }
        }
        public static readonly DependencyProperty ProgressPauseColorProperty = DependencyProperty.Register("ProgressPauseColor", typeof(Brush), typeof(ModernProgressBar), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(255, 168, 72))));

        public Brush ProgressBackgroundColor
        {
            get { return (Brush)GetValue(ProgressBackgroundColorProperty); }
            set { SetValue(ProgressBackgroundColorProperty, value); }
        }
        public static readonly DependencyProperty ProgressBackgroundColorProperty = DependencyProperty.Register("ProgressBackgroundColor", typeof(Brush), typeof(ModernProgressBar), new PropertyMetadata(Brushes.Transparent));

        public Brush ProgressBarBorderBrush
        {
            get { return (Brush)GetValue(ProgressBarBorderBrushProperty); }
            set { SetValue(ProgressBarBorderBrushProperty, value); }
        }
        public static readonly DependencyProperty ProgressBarBorderBrushProperty = DependencyProperty.Register("ProgressBarBorderBrush", typeof(Brush), typeof(ModernProgressBar), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(152, 152, 231))));

        public Thickness ProgressBarBorderThickness
        {
            get { return (Thickness)GetValue(ProgressBarBorderThicknessProperty); }
            set { SetValue(ProgressBarBorderThicknessProperty, value); }
        }
        public static readonly DependencyProperty ProgressBarBorderThicknessProperty = DependencyProperty.Register("ProgressBarBorderThickness", typeof(Thickness), typeof(ModernProgressBar), new PropertyMetadata(new Thickness(1)));
        #endregion

        public ModernProgressBar()
        {
            InitializeComponent();
        }

        private double GetPercent() => Value / (MaxValue - MinValue);
        private double GetBottomWidth() => progressBarBottom.ActualWidth;
        private double GetTargetTopWidth() => GetBottomWidth() * GetPercent();
        private void SetTopWidth()
        {
            if (!IsBusy)
                progressBarTop.Width = GetTargetTopWidth();
        }

        public void Update() => SetTopWidth();

        private void ApplyBusyAnimation()
        {
            progressBarTop.Visibility = Visibility.Collapsed;
            progressBarAnimationTop.Visibility = Visibility.Visible;
            progressBarTranslateTransform.BeginAnimation(TranslateTransform.XProperty, null);
            progressBarScaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
            var animation = new DoubleAnimation
            {
                From = -25,
                To = GetBottomWidth() - 25,
                EasingFunction = new CubicEase
                {
                    EasingMode = EasingMode.EaseInOut
                },
                Duration = TimeSpan.FromMilliseconds(1000),
                RepeatBehavior = RepeatBehavior.Forever
            };
            var scaleAnimation = new DoubleAnimation
            {
                From = 0,
                To = 1,
                EasingFunction = new CubicEase
                {
                    EasingMode = EasingMode.EaseInOut
                },
                Duration = TimeSpan.FromMilliseconds(500),
                RepeatBehavior = RepeatBehavior.Forever,
                AutoReverse = true
            };
            progressBarTranslateTransform.BeginAnimation(TranslateTransform.XProperty, animation);
            progressBarScaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
        }

        private void RemoveBusyAnimation()
        {
            progressBarTop.Visibility = Visibility.Visible;
            progressBarAnimationTop.Visibility = Visibility.Collapsed;
            progressBarTranslateTransform.BeginAnimation(TranslateTransform.XProperty, null);
            progressBarScaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
        }

        public void SetBusy()
        {
            if (IsBusy && !IsPause && !IsError)
            {
                ApplyBusyAnimation();
            }
            else if (!IsBusy)
            {
                if (IsPause)
                    SetPause();
                else if (IsError)
                    SetError();
                else
                    RemoveBusyAnimation();
            }
        }

        public void SetPause()
        {
            if (IsPause)
            {
                RemoveBusyAnimation();
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressPauseColor,
                    Mode = BindingMode.OneWay
                });
            }
            else if (IsError)
            {
                RemoveBusyAnimation();
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressErrorColor,
                    Mode = BindingMode.OneWay
                });
            }
            else
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressColor,
                    Mode = BindingMode.OneWay
                });
        }

        public void SetError()
        {
            if (IsError)
            {
                RemoveBusyAnimation();
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressErrorColor,
                    Mode = BindingMode.OneWay
                });
            }
            else if (IsPause)
            {
                RemoveBusyAnimation();
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressPauseColor,
                    Mode = BindingMode.OneWay
                });
            }
            else
                progressBarTop.SetBinding(Border.BackgroundProperty, new Binding
                {
                    Source = ProgressColor,
                    Mode = BindingMode.OneWay
                });
        }

        private void ModernProgressBar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (!IsBusy)
                SetTopWidth();
        }

        private void ModernProgressBar_Loaded(object sender, RoutedEventArgs e)
        {
            SetTopWidth();
            SetBusy();
            SetPause();
            SetError();
        }
    }
}