在WPF应用程序中,我们有一个按钮,用户可以单击该按钮来触发要加载到VLC Media Player中的视频列表:
<Button Content="{Binding RotatorButtonLabel}" Command="{Binding RotateVideosCommand}" />
在 View 模型
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,但它假设任务和 Activity 都在一个类中。在这里,我有一个 View 模型和一个后台代码。谢谢你。
最佳答案
您不能(以实用的方式)也不应这样做。
如果要停止在另一个线程中工作,那么正确的方法是向该线程发出信号(就像您已经完成的那样),并允许该线程自己停止。由于您的示例工作负载是Thread.Sleep(5000)
,一旦被点击,该线程将无法执行任何其他操作,直到 sleep 时间结束。换句话说,您可以正确地向线程发出信号,并且如果线程正在 sleep ,它将一直存活直到 sleep 完成,然后它将再次检查该信号。
选项:
Token
传递给模拟的工作负载使用
Task.Wait(5000, token)
并使用它代替Thread.Sleep(5000)
。这样,模拟工作也可以取消。
何时何地看起来很公平,这样您就不必长时间等待
发出取消信号时返回的时间。请注意,让调用者等待
Thread
或Task
本身正确结束是最好的方法它。这就是
Thread.Abort
受到如此多批评的原因,灰心。
Cancel()
,然后继续进行操作,而无需等待Task
或Thread
完成。您必须牢记这一点,但是这是实用的。 关于c# - 允许用户从按钮立即取消长时间运行的WPF操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54354587/