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