简体   繁体   English

WPF如何在控件事件中等待代码

[英]WPF how to await code inside controls events

I am using a 3rd party library that i cannot change how it functions. 我正在使用第3方库,但无法更改其功能。 It is a lib wrapper that allows me to adjust video filters such as brightness and contrast on video files using the FFMPEG lib. 它是一个lib包装程序,使我可以使用FFMPEG lib调整视频文件的视频过滤器,例如亮度和对比度。

I am trying to use a slider/trackbar in WPF to provide a slider to adjust the contrast level to this lib I have this code 我正在尝试在WPF中使用滑块/轨迹栏来提供一个滑块来将对比度级别调整为此lib我有此代码

 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;
  }

this works briefly (i can see the contrast of the video change) before the application just closes with no errors or exceptions. 在应用程序关闭之前,没有任何错误或异常,这可以短暂地起作用(我可以看到视频变化的对比度)。 I have enabled all exceptions in VS and nothing gets trapped. 我在VS中启用了所有异常,没有任何异常。

"ChangeMedia();" “ ChangeMedia();” is a function in the 3rd party lib and it seems from my testing that calling it too many times before it completes its function is causing the issue. 是第3方库中的一个函数,从我的测试看来,在完成其功能之前多次调用它会导致问题。 My best guess is there is something like overflow situation occurring causing the application to shut down. 我最好的猜测是,发生类似溢出的情况,导致应用程序关闭。

But if i use this code below i can call as much as i like in rapid execution with no problem. 但是,如果我在下面使用此代码,则我可以快速调用任意数量的代码,而不会出现任何问题。

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);
            }
        }
    }

this tells me calling player.UpdateVideoFilter from inside the slider control event it does not await the call to the function but makes concurrent calls with every change of the slider value causing it to crash 这告诉我从滑块控件事件内部调用player.UpdateVideoFilter时,它不等待对函数的调用,而是在滑块值每次更改时并发调用,从而导致崩溃

So how can i do this. 那么我该怎么做。 How do i provide a good user experience where they can smoothly change values using the slider control, in a manner the user would expect. 我如何提供良好的用户体验,使他们可以按照用户期望的方式使用滑块控件平滑地更改值。

I need to find a way to make code called in a control event await the call to await player.UpdateVideoFilter before the next execution. 我需要找到一种方法来使在控制事件中调用的代码在下一次执行之前等待调用play.UpdateVideoFilter的调用。

The time taken for the await to return is not significant enough as far as i can see to block the slider control function. 据我所知,等待返回所花费的时间不足以阻止滑块控制功能。 I just need it to await. 我只需要它等待。

Any advice appreciated. 任何建议表示赞赏。

The problem is that event handlers are async void methods, which cannot be await ed. 问题在于事件处理程序是async void方法,无法await WPF (and other UI frameworks) will allow as many event handlers to fire as the user requests. WPF(和其他UI框架)将允许根据用户请求触发尽可能多的事件处理程序。

For some UI elements - such as buttons - the standard approach is to disable the button at the beginning of the handler and re-enable it at the end. 对于某些UI元素(例如按钮),标准方法是在处理程序的开头禁用按钮,并在结尾处重新启用按钮。 This is an easy way to prevent multiple asynchronous handlers from running simultaneously. 这是防止多个异步处理程序同时运行的简便方法。

In your example, where the user can change the slider a lot over a short period of time, I would recommend using Channels . 在您的示例中,用户可以在短时间内大量更改滑块,我建议您使用Channels Channels are like producer/consumer queues that can be bounded and have built-in logic for how to handle when too many items come in at once ("back pressure"). 通道就像可以限制的生产者/消费者队列, 具有内置的逻辑来处理如何一次处理太多物品(“背压”)。

So you could have a bounded channel of size 1 that discards older entries, like this: 因此,您可能有一个大小为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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM