I want to make a timer app where various timers are started asynchronously and then update the ui with each tick. (I'm doing this to learn the TPL library). But for some reason my code seems to hang.
I have three layers. The first is my WPF program, when I click on a button, I can create a new timer which is added to the panel
private void AddStopwatch_OnClick(object sender, RoutedEventArgs e)
{
var labelInput = new InputBox();
labelInput.ShowDialog();
if (labelInput.Result != MessageBoxResult.OK) return;
var timer = new DisplayTimer(labelInput.Text);
timer.Stopwatch = new AsyncStopwatchTimer(new Progress<TimeSpan>(async t =>
{
timer.Time = t;
await Task.Delay(1000);
}));
_timers.Add(timer.Stopwatch);
Panel.Children.Add(timer);
}
In the
timer
I have a button that starts and stops my timer. I used a RelativeSource Self to bind the Time dependency property to a label, so I just update the Time prop and that updates my label.
private void StartStop_OnClick(object sender, RoutedEventArgs e)
{
if (Stopwatch.IsStarted)
{
Stopwatch.Stop();
Time = Stopwatch.GetDuration();
StartStop.Content = "Start";
}
else
{
Stopwatch.Start();
StartStop.Content = "Stop";
}
}
And lastly, I have my timer start function that runs my progress update in a loop so it keeps updating the UI (or that's what I hope). If you noticed I put the delay in the progress, so the program is fully capable of telling how many times the UI should update.
I also have a stop function that should cancel the task that was started in the Start() method so the task doesn't keep looping endlesly.
public async void Start()
{
if (IsStarted) return;
_cts = new CancellationTokenSource();
_start = SystemClock.Instance.Now;
IsStarted = true;
await Task.Factory.StartNew(() =>
{
while (true)
{
if (_progress != null)
_progress.Report(GetDuration());
if (_cts.Token.IsCancellationRequested)
return;
}
}, _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
}
public void Stop()
{
if (!IsStarted) return;
Instant end = SystemClock.Instance.Now;
_intervals.Add(Duration.FromTicks(end.Ticks - _start.Ticks));
IsStarted = false;
_cts.Cancel();
}
Everything works fine until I press the "Start" button. Then the program just freezes up. Any ideas why? If you need more info, just ask and ye shall receive.
UPDATE : I found out that the code in AddStopwatch_OnClick keeps blocking the thread.
{
timer.Time = t;
await Task.Delay(1000);
}
This should be run async, but it's being run on the UI thread, thus blocking the whole UI.