C# System.Threading.Tasks.TaskCanceledException:&x27;一项任务被取消;关闭应用程序时
我有一根线可以改变这个领域C# System.Threading.Tasks.TaskCanceledException:&x27;一项任务被取消;关闭应用程序时,c#,multithreading,exception,C#,Multithreading,Exception,我有一根线可以改变这个领域 private void SongChange(object sender, RoutedEventArgs e) { SongChangeAction(); songLength = (int)BGMPlayer.NaturalDuration.TimeSpan.TotalSeconds; songProgress = new Thread(SongProgressUpdate) { IsBackground
private void SongChange(object sender, RoutedEventArgs e)
{
SongChangeAction();
songLength = (int)BGMPlayer.NaturalDuration.TimeSpan.TotalSeconds;
songProgress = new Thread(SongProgressUpdate) { IsBackground = true };
songProgress.Start();
}
private void SongProgressUpdate()
{
while (true)
{
Dispatcher.Invoke(() => { workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100; });
Thread.Sleep(1000);
}
}
注:songLength
是一个double
,bMPlayer
是一个MediaElement
在后台播放音乐,工作资源。SongProgress
是一个双绑定到进度条
当我使用“X”按钮或任务栏关闭程序时,程序抛出异常System.Threading.Tasks.TaskCanceledException
即使我尝试设置线程IsBackground=true
,但如果我使用Visual Studio停止程序,它也不会抛出异常。
程序在第行抛出异常:
Dispatcher.Invoke(() => { workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100; });
我可以通过使用try/catch来防止它,但我想找到更有效的方法尝试使用Microsoft的反应式框架。然后你可以这样做:
private void SongChange(object sender, RoutedEventArgs e)
{
SongChangeAction();
songLength = (int)BGMPlayer.NaturalDuration.TimeSpan.TotalSeconds;
IDisposable subscription =
Observable
.Interval(TimeSpan.FromSeconds(1.0))
.ObserveOnDispatcher()
.Subscribe(x => workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100);
}
您只需确保保存对subscription
的引用,并在关闭应用程序时调用.Dispose()
NuGet“System.Reactive”和“System.Reactive.Windows.Threading”,并使用System.Reactive.Linq添加代码>添加到您的代码。在窗口关闭时尝试使用取消令牌
:
private readonly CancellationTokenSource _shutDown = new CancellationTokenSource();
public WindowName()
{
this.Closed =+ (s, e) => this._shutDown.Cancel();
}
private void SongChange(object sender, RoutedEventArgs e)
{
SongChangeAction();
songLength = (int)BGMPlayer.NaturalDuration.TimeSpan.TotalSeconds;
songProgress = Task.Factory.StartNew(SongProgressUpdate, this._shutDown.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
private void SongProgressUpdate()
{
while (!this._shutDown.IsCancellationRequested)
{
Dispatcher.Invoke(() => { workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100; });
Thread.Sleep(1000);
}
}
在你的情况下,这是意料之中的例外。当您关闭主窗口时,WPF将优雅地关闭。若您尝试在Dispatcher开始关闭时执行Dispatcher.Invoke
,它将抛出您看到的异常。您可以切换到BeginInvoke
,捕获该异常,或者更好地使用其他不需要调度程序的方法来实现目标。调用、分离线程和,而(true)
循环。bgmlayer是一个控件。如果我使用另一个线程作为use while循环,那么应用程序将抛出thread.invalidooperation