Reputation: 232
I have a thread that change the field
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);
}
}
Note: songLength
is a double
, BGMPlayer
is a MediaElement
to play music in background, workingResources.SongProgress
is a double
bind to a Progress Bar
When I close the Program using "X" button or on taskbar, The program threw exception System.Threading.Tasks.TaskCanceledException
Even I try to set the thread IsBackground = true
but it work not throw exception If I stop the program using Visual Studio.
The Program Throw exception at line:
Dispatcher.Invoke(() => { workingResources.SongProgress = BGMPlayer.Position.TotalSeconds / songLength * 100; });
I can prevent it by using try/catch but I want to find something more efficient
Upvotes: 1
Views: 5261
Reputation: 2663
Try using a CancellationToken
on close of the window:
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);
}
}
Upvotes: 2
Reputation: 117064
Try using Microsoft's Reactive Framework. Then you can do this:
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);
}
You just need to make sure that you save a reference to subscription
and call .Dispose()
on it when you are closing your app.
NuGet "System.Reactive" and "System.Reactive.Windows.Threading", and add using System.Reactive.Linq;
to your code.
Upvotes: 1