System.Threading.Tasks.TaskCanceledException:'任务被取消。'何时关闭应用

时间:2018-05-16 11:55:32

标签: c# multithreading exception

我有一个改变字段的线程

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);
        }
    }

注意:songLengthdoubleBGMPlayerMediaElement在后​​台播放音乐,workingResources.SongProgressdouble绑定到一个Progress Bar

当我使用" X"关闭程序时按钮或在任务栏上,程序抛出异常System.Threading.Tasks.TaskCanceledException即使我尝试设置线程IsBackground = true但它不会抛出异常如果我使用Visual Studio停止程序。 行中的程序抛出异常:

Dispatcher.Invoke(() => { workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100; });

我可以通过使用try / catch来阻止它,但我想找到更高效的东西

2 个答案:

答案 0 :(得分:1)

尝试使用Microsoft的Reactive Framework。然后你可以这样做:

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”,并将using System.Reactive.Linq;添加到您的代码中。

答案 1 :(得分:1)

尝试在窗口关闭时使用CancellationToken

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);
    }
}