我正在使用第三方库,我无法改变其运作方式。它是一个lib包装器,允许我使用FFMPEG lib调整视频文件上的视频滤镜,如亮度和对比度。
我试图在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;
}
这可以简单地工作(我可以看到视频更改的对比)在应用程序关闭之前没有错误或异常。我在VS中启用了所有异常,没有任何东西被困。
“ChangeMedia();”是第三方库中的一个函数,从我的测试看来,在它完成其功能之前调用它太多次都会导致问题。我最好的猜测是有一些像溢出情况发生导致应用程序关闭。
但是,如果我使用下面的代码,我可以在快速执行中尽可能多地调用,没有任何问题。
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它不会等待对函数的调用,但是每次更改滑块值都会进行并发调用,导致它崩溃
那我怎么能这样做呢。如何使用滑块控件以用户期望的方式平滑地更改值,从而提供良好的用户体验。
我需要找到一种方法来使控件事件中调用的代码等待在下次执行之前调用await player.UpdateVideoFilter。
只要我能看到阻止滑块控制功能,等待返回所花费的时间就不够了。我只需要它等待。
任何建议表示赞赏
问题是事件处理程序是async void
方法,不能用await
ed。 WPF(以及其他UI框架)将允许在用户请求时触发尽可能多的事件处理程序。
对于某些UI元素 - 例如按钮 - 标准方法是在处理程序的开头禁用按钮并在结束时重新启用它。这是防止多个异步处理程序同时运行的简单方法。
在您的示例中,用户可以在很短的时间内更改滑块,我建议使用Channels。频道就像是生产者/消费者队列,它们可以是有界的,并且具有内置逻辑,用于在有太多物品进入的同时处理(“背压”)。
所以你可以有一个大小为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);
}