【发布时间】:2019-01-24 20:10:39
【问题描述】:
在 WPF 应用程序中,我们有一个按钮,用户可以单击该按钮来触发要加载到 VLC 媒体播放器中的视频列表:
<Button Content="{Binding RotatorButtonLabel}" Command="{Binding RotateVideosCommand}" />
在视图模型MainWindowVm中,我们有处理按钮点击的命令:
public ICommand RotateVideosCommand => new RelayCommand(RotateVideos);
private void RotateVideos()
{
IsRotatorActive = !IsRotatorActive;
RotatorButtonLabel = IsRotatorActive
? "Stop Rotator"
: "Rotate Videos";
_rotatorVm = new RotatorVm
{
ImageVms = ImagesView.Cast<ImageVm>().ToList(),
IsRotatorActive = IsRotatorActive
};
// This fires off a new thread to run the rotator, otherwise the UI freezes.
Task.Run(() => Messenger.Default.Send(rotatorVm, "LaunchRotator"));
}
注意在上述命令处理程序中,我们使用 MVVM Light Toolkit 的 Messenger 告诉代码隐藏启动旋转器。
现在在MainWindow.xaml.cs,我们有以下c'tor:
private CancellationTokenSource _cancellationTokenSource = null;
private CancellationToken _cancellationToken;
public MainWindow()
{
InitializeComponent();
Messenger.Default.Register<RotatorVm>(this, "LaunchRotator", LaunchRotator);
// Other logic...
}
然后这就是上面LaunchRotator 所说的:
private void LaunchRotator(RotatorVm rotatorVm)
{
if (_cancellationToken.IsCancellationRequested)
{
_cancellationTokenSource.Dispose();
}
if (_cancellationTokenSource == null || _cancellationToken.IsCancellationRequested)
{
_cancellationTokenSource = new CancellationTokenSource();
_cancellationToken = _cancellationTokenSource.Token;
}
if (!rotatorVm.IsRotatorActive)
{
_cancellationTokenSource.Cancel();
return;
}
RotateVideos();
}
private void RotateVideos()
{
while (true)
{
if (_cancellationToken.IsCancellationRequested)
{
return;
}
// This is to simplify the code and simulate work.
Thread.Sleep(5000);
}
}
如果我单击“停止旋转器”按钮,代码可能需要几秒钟才能到达while 循环的下一次迭代并读取IsCancellationRequested。在这种情况下如何让它立即停止?
我看过this example,但它假设任务和活动都在一个类中;在这里,我有一个视图模型和一个代码隐藏。谢谢。
【问题讨论】:
-
你能在主要工作中更频繁地测试
IsCancellationRequested吗? -
@redcurry,当你说“主要工作”时,你的意思是在
RotateVideos方法中吗? -
是的,特别是被
Thread.Sleep(5000)替换的作品。 -
这将启动 VLC,然后
Timer(未显示)上的事件处理程序将切换视频。也许启动 VLC 进程不会花那么长时间,所以当用户点击停止时,他们会相对较快地终止操作。