Задержка с привязкой WPF - PullRequest
0 голосов
/ 05 апреля 2019

Я пытаюсь создать 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);
}

Работает нормально, но я не знаю, могу ли я найти другое решение.

...