在WPF应用中,我们有一个按钮,用户可以单击该按钮来触发要加载到VLC Media Player中的视频列表:
<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
中,我们有以下代码:
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,但这是假设任务和活动都在一个班级中。在这里,我有一个视图模型和一个后台代码。谢谢。
答案 0 :(得分:2)
您不能(实际上)也不应该。
如果要停止在另一个线程中工作,那么正确的方法是向该线程发出信号(就像您已经完成的那样),并允许该线程自己停止。由于您的示例工作负载是Thread.Sleep(5000)
,因此一旦被点击,该线程将无法执行任何其他操作,直到睡眠时间到期为止。换句话说,您可以正确发出信号,如果该线程处于睡眠状态,则该线程将一直存活直到睡眠完成,然后它将再次检查该信号。
选项:
Token
传递给模拟的工作负载
使用Task.Wait(5000, token)
并使用它代替
Thread.Sleep(5000)
。这样,模拟工作也可以
已取消。Thread
或Task
正确地结束自身是最好的方法
它。这就是Thread.Abort
受到如此多批评并且是
灰心丧气。Cancel()
,然后继续进行而不必等待Task
或Thread
完成。您必须在设计时考虑到这一点,但这是实用的。