|
|
@@ -22,7 +22,7 @@ namespace Avalonia.Controls
|
|
|
AvaloniaProperty.Register<ProgressBar, Orientation>(nameof(Orientation), Orientation.Horizontal);
|
|
|
|
|
|
private Border _indicator;
|
|
|
- private IDisposable _indeterminateBindSubscription;
|
|
|
+ private IndeterminateAnimation _indeterminateAnimation;
|
|
|
|
|
|
static ProgressBar()
|
|
|
{
|
|
|
@@ -30,26 +30,23 @@ namespace Avalonia.Controls
|
|
|
|
|
|
HorizontalAlignmentProperty.OverrideDefaultValue<ProgressBar>(HorizontalAlignment.Left);
|
|
|
VerticalAlignmentProperty.OverrideDefaultValue<ProgressBar>(VerticalAlignment.Top);
|
|
|
+
|
|
|
+ IsIndeterminateProperty.Changed.AddClassHandler<ProgressBar>(
|
|
|
+ (p, e) => { if (p._indicator != null) p.UpdateIsIndeterminate((bool)e.NewValue); });
|
|
|
+ OrientationProperty.Changed.AddClassHandler<ProgressBar>(
|
|
|
+ (p, e) => { if (p._indicator != null) p.UpdateOrientation((Orientation)e.NewValue); });
|
|
|
}
|
|
|
|
|
|
public bool IsIndeterminate
|
|
|
{
|
|
|
get => GetValue(IsIndeterminateProperty);
|
|
|
- set
|
|
|
- {
|
|
|
- SetValue(IsIndeterminateProperty, value);
|
|
|
- UpdateIsIndeterminate(value);
|
|
|
- }
|
|
|
+ set => SetValue(IsIndeterminateProperty, value);
|
|
|
}
|
|
|
|
|
|
public Orientation Orientation
|
|
|
{
|
|
|
get => GetValue(OrientationProperty);
|
|
|
- set
|
|
|
- {
|
|
|
- SetValue(OrientationProperty, value);
|
|
|
- UpdateOrientation(value);
|
|
|
- }
|
|
|
+ set => SetValue(OrientationProperty, value);
|
|
|
}
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
@@ -115,33 +112,66 @@ namespace Avalonia.Controls
|
|
|
private void UpdateIsIndeterminate(bool isIndeterminate)
|
|
|
{
|
|
|
if (isIndeterminate)
|
|
|
+ _indeterminateAnimation = IndeterminateAnimation.StartAnimation(this);
|
|
|
+ else
|
|
|
+ _indeterminateAnimation?.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ UpdateIndicator(Bounds.Size);
|
|
|
+ }
|
|
|
+
|
|
|
+ private class IndeterminateAnimation : IDisposable
|
|
|
+ {
|
|
|
+ private WeakReference<ProgressBar> _progressBar;
|
|
|
+ private IDisposable _indeterminateBindSubscription;
|
|
|
+ private TimeSpan _startTime;
|
|
|
+
|
|
|
+ private IndeterminateAnimation(ProgressBar progressBar)
|
|
|
+ {
|
|
|
+ _progressBar = new WeakReference<ProgressBar>(progressBar);
|
|
|
+ _startTime = Animate.Stopwatch.Elapsed;
|
|
|
+ _indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - _startTime).TotalSeconds <= 4.0)
|
|
|
+ .Select(GetAnimationRect)
|
|
|
+ .Finally(() => _startTime = Animate.Stopwatch.Elapsed)
|
|
|
+ .Repeat()
|
|
|
+ .Subscribe(AnimationTick);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static IndeterminateAnimation StartAnimation(ProgressBar progressBar)
|
|
|
{
|
|
|
- var start = Animate.Stopwatch.Elapsed;
|
|
|
+ return new IndeterminateAnimation(progressBar);
|
|
|
+ }
|
|
|
|
|
|
- if (Orientation == Orientation.Horizontal)
|
|
|
+ private Rect GetAnimationRect(TimeSpan time)
|
|
|
+ {
|
|
|
+ if (_progressBar.TryGetTarget(out var progressBar))
|
|
|
{
|
|
|
- _indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - start).TotalSeconds <= 4.0)
|
|
|
- .Select(x => new Rect(-_indicator.Width - 5 + (x - start).TotalSeconds / 4.0 * (Bounds.Width + _indicator.Width + 10), 0, _indicator.Bounds.Width, _indicator.Bounds.Height))
|
|
|
- .Finally(() => start = Animate.Stopwatch.Elapsed)
|
|
|
- .Repeat()
|
|
|
- .Subscribe(x => _indicator.Arrange(x));
|
|
|
+ if (progressBar.Orientation == Orientation.Horizontal)
|
|
|
+ return new Rect(-progressBar._indicator.Width - 5 + (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Width + progressBar._indicator.Width + 10), 0, progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
|
|
|
+ else
|
|
|
+ return new Rect(0, progressBar.Bounds.Height + 5 - (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Height + progressBar._indicator.Height + 10), progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- _indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - start).TotalSeconds <= 4.0)
|
|
|
- .Select(x => new Rect(0, Bounds.Height + 5 - (x - start).TotalSeconds / 4.0 * (Bounds.Height + _indicator.Height + 10), _indicator.Bounds.Width, _indicator.Bounds.Height))
|
|
|
- .Finally(() => start = Animate.Stopwatch.Elapsed)
|
|
|
- .Repeat()
|
|
|
- .Subscribe(x => _indicator.Arrange(x));
|
|
|
+ _indeterminateBindSubscription.Dispose();
|
|
|
+ return Rect.Empty;
|
|
|
}
|
|
|
}
|
|
|
- else
|
|
|
- _indeterminateBindSubscription?.Dispose();
|
|
|
- }
|
|
|
|
|
|
- private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
|
|
|
- {
|
|
|
- UpdateIndicator(Bounds.Size);
|
|
|
+ private void AnimationTick(Rect rect)
|
|
|
+ {
|
|
|
+ if (_progressBar.TryGetTarget(out var progressBar))
|
|
|
+ progressBar._indicator.Arrange(rect);
|
|
|
+ else
|
|
|
+ _indeterminateBindSubscription.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ _indeterminateBindSubscription?.Dispose();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|