Я пытаюсь создать ProgressBar
, который может анимировать от 0 до некоторого значения.В большинстве случаев все работает нормально ...
Я использую код Оуэн Джонсон .Есть некоторые изменения, такие как:
public static readonly DependencyProperty SmoothValueProperty =
DependencyProperty.RegisterAttached("SmoothValue", typeof(double), typeof(ProgressBarSmoother),
new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, changing, coerceValueCallback, false, System.Windows.Data.UpdateSourceTrigger.PropertyChanged));
private static object coerceValueCallback(DependencyObject d, object baseValue)
{
Console.WriteLine($"{ (double)baseValue } coercevalue");
return baseValue;
}
public static void changing(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ProgressBarSmoother obj = d as ProgressBarSmoother;
Console.WriteLine($"Contador: {++obj.Count}. Valor novo: { e.NewValue }");
if ((double)e.NewValue == 0)
{
obj.ResetAnimation();
Console.WriteLine($"Contador: {++obj.Count}");
obj.Value = 0;
return;
}
obj.Animation = new DoubleAnimation(0d, (double)e.NewValue, TimeSpan.FromMilliseconds((double)e.NewValue));
obj.Animation.Completed += (sender, arg) =>
{
obj.Animation = null;
obj.Value = 0;
obj.BeginAnimation(ValueProperty, null, HandoffBehavior.SnapshotAndReplace);
Console.WriteLine("Animation completed");
};
obj.Foreground = new SolidColorBrush(Colors.Red);
obj.BeginAnimation(ValueProperty, obj.Animation, HandoffBehavior.SnapshotAndReplace);
Console.WriteLine($"Contador: {++obj.Count}");
}
// Basically the code that changes the progressbar value is this
private void Controller_OnPlayerChangedState(object sender, MultiPlayerController.OnChangeStateEventArgs e)
{
if (e.NewState == AudioPlayer_State.Playing)
{
Duration = AudioPanel.Controller.GetDuration();
panel.SetCurrentPositionAsync (Duration);
}
else if(e.NewState != AudioPlayer_State.Playing && e.NewState != AudioPlayer_State.Paused)
{
panel.SetCurrentPositionAsync ((long)0);
//System.Threading.Thread.Sleep(100);
}
}
(есть много кода только для теста и посмотрите, что радует)
У меня есть аудиоплеер, а progressbar
- чтобы увидеть реальныйположение звука (не может быть приостановлено, только остановлено).Кнопка Стоп работает отлично.Проблема в том, что статус повтора активирован.Я получаю событие из моей dll of Stopped (установите значение 0, и моя анимация исчезнет), а через несколько мгновений (в большинстве случаев менее 0 мс) происходит воспроизведение, поэтому я должен обновить анимацию progressbar
с продолжительностью.
Иногда моя анимация не вызывается, и я помещаю некоторые логи, чтобы узнать, что.Когда не вызывается, CoerceValueCallback
происходит только один раз.А когда работает, вызывается два раза: один с 0, когда я уничтожаю старую анимацию, а другой с новой продолжительностью (такой же, как и раньше).
Просто для теста я поместил Thread.Sleep
внутри кода, который изменяет значение на новую продолжительность и работает как талисман.Я думаю, задержка, чтобы изменить новое значение ... В основном мне нужно установить на 0, а после на новое значение.
Можно ли убрать проверку, если старое значение должно отличаться от более нового?Или я могу мгновенно обновить значение?
Решение до этого момента
Я создал открытую функцию на своем контроле ProgressBarSmoother
с именем ResetAnimation
public void ResetAnimation()
{
this.Dispatcher.Invoke(() =>
{
SmoothValue = 0;
});
}
И создалgetter/setter
из SmoothValue
public double SmoothValue
{
get => (double)GetValue(SmoothValueProperty);
set => SetValue(SmoothValueProperty, value);
}
На моем SetCurrentPositionAsync
,
public void SetCurrentPositionAsync (long position)
{
if (position == 0)
progressBar.ResetAnimation();
CurrentPositionAsync = position;
}
И мои изменения:
public static void changing(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ProgressBarSmoother obj = d as ProgressBarSmoother;
if ((double)e.NewValue == 0)
{
obj.BeginAnimation(ValueProperty, null, HandoffBehavior.SnapshotAndReplace);
return;
}
obj.Animation = new DoubleAnimation(0d, (double)e.NewValue, TimeSpan.FromMilliseconds((double)e.NewValue));
obj.BeginAnimation(ValueProperty, obj.Animation, HandoffBehavior.SnapshotAndReplace);
}
Итак .. Когда яустановив 0, я сразу же вызываю ResetAnimation
, который может установить значение свойства и правильно установить поле вместо вызова OnPropertyChanged
и с некоторой задержкой.
Мой Controller_OnPlayerChangedState
:
private void Controller_OnPlayerChangedState(object sender, MultiPlayerController.OnChangeStateEventArgs e)
{
if (e.NewState == AudioPlayer_State.Playing)
{
Duration = AudioPanel.Controller.GetDuration();
panel.SetCurrentPositionAsync((long)Duration);
}
else if(e.NewState != AudioPlayer_State.Playing && e.NewState != AudioPlayer_State.Paused)
panel.SetCurrentPositionAsync(0);
}
Работает нормально, но я не знаю, могу ли я найти другое решение.