WPF как ждать кода внутри элементов управления событиями - PullRequest
0 голосов
/ 22 апреля 2019

Я использую стороннюю библиотеку, которую не могу изменить, как она работает. Это оболочка lib, которая позволяет мне настраивать видео фильтры, такие как яркость и контрастность видеофайлов, используя FFMPEG lib.

Я пытаюсь использовать ползунок / трекбар в WPF, чтобы предоставить ползунок для настройки уровня контрастности в этой библиотеке У меня есть этот код

 private async void TbeVolumeLevel_EditValueChanged(object sender, 
 DevExpress.Xpf.Editors.EditValueChangedEventArgs e)
    {
      bool x = await _PlayerList[0].UpdateVideoFilter("eq=contrast="+ 
      e.NewValue.ToString());

    }

public async Task<bool> UpdateVideoFilter(string sFilter)
  {           
    _Filter = sFilter;
    x = await MEMediaPlayer.ChangeMedia();
       return x;
  }

это работает кратко (я вижу контраст изменения видео), прежде чем приложение просто закроется без ошибок или исключений. Я включил все исключения в VS и ничего не попало в ловушку.

"ChangeMedia ();" является функцией в сторонней библиотеке lib, и из моего тестирования видно, что вызов ее слишком много раз, прежде чем она завершит свою функцию, вызывает проблему. Мое лучшее предположение - что-то вроде ситуации переполнения, приводящей к закрытию приложения.

Но если я использую этот код, приведенный ниже, я могу вызывать сколько угодно в быстром исполнении без проблем.

private async void BtnPlay_Click(object sender, RoutedEventArgs e)
    {
     for (int i = 1; i < 20; i++)
        {
            foreach (FFMEBaseVideoPlayer player in _PlayerList)
            {
                var x = await player.UpdateVideoFilter("eq=contrast=" + (i/10));
              Debug.WriteLine(i);
            }
        }
    }

это говорит мне о вызове player.UpdateVideoFilter изнутри события управления ползунком, оно не ожидает вызова функции, а выполняет параллельные вызовы при каждом изменении значения ползунка, приводящем к сбою

Так как я могу это сделать. Как обеспечить хороший пользовательский опыт, когда они могут плавно изменять значения с помощью ползунка, как и ожидал пользователь.

Мне нужно найти способ сделать так, чтобы код, вызываемый в управляющем событии, ожидал вызова ожидающего player.UpdateVideoFilter перед следующим выполнением.

Время, затраченное на ожидание возврата, недостаточно, насколько я вижу, чтобы заблокировать функцию управления ползунком. Мне просто нужно это дождаться.

Любой совет приветствуется.

1 Ответ

2 голосов
/ 22 апреля 2019

Проблема в том, что обработчиками событий являются async void методы, которые не могут быть await ed.WPF (и другие инфраструктуры пользовательского интерфейса) позволяют запускать столько обработчиков событий, сколько запрашивает пользователь.

Для некоторых элементов пользовательского интерфейса, таких как кнопки, стандартным подходом является отключение кнопки в начале обработчика ивключите его в конце.Это простой способ предотвратить одновременную работу нескольких асинхронных обработчиков.

В вашем примере, где пользователь может сильно изменить ползунок за короткий промежуток времени, я бы рекомендовал использовать Каналы * 1008.*.Каналы похожи на очереди производителей / потребителей, которые могут быть ограничены и имеют встроенную логику для обработки, когда одновременно поступает слишком много элементов («обратное давление»).

Таким образом, выможет иметь ограниченный канал размером 1, который отбрасывает более старые записи, например:

private readonly Channel<string> _contrastValue = Channel.CreateBounded<string>(new BoundedChannelOptions
{
  Capacity = 1,
  FullMode = BoundedChannelFullMode.DropOldest,
});

// You'll need to start this consumer somewhere and observe it (via await) to ensure you see exceptions
private async Task ConsumeContrastValueAsync()
{
  var reader = _contrastValue.Reader;
  while (await reader.WaitToReadAsync(CancellationToken.None))
    while (reader.TryRead(out var value))
      await _PlayerList[0].UpdateVideoFilter("eq=contrast=" + value);
}

private async void TbeVolumeLevel_EditValueChanged(object sender, DevExpress.Xpf.Editors.EditValueChangedEventArgs e)
{
  await _contrastValue.Writer.WriteAsync(e.NewValue.ToString(), CancellationToken.None);
}
...