У меня есть приложение для управления светодиодной лентой. Пользовательский интерфейс имеет выпадающий список с выбором эффекта, и когда пользователь выбирает режим, он ожидает завершения текущего цикла эффектов, вызывая StopTask (), а затем выполняет выбранный эффект. Он посылает цвет светодиодов и т. Д. В Arduino через последовательный порт. Это работает.
Проблема в том, что когда я запускаю StopTask () с помощью MainWindow_OnClosing (когда пользователь выходит из приложения), он вызывает StopTask (), но застревает в ожидании currentEffectMode. Я попытаюсь объяснить это больше комментариями внутри кода
Выбор режима MainWindow:
private void CbMode_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Checkbox selection triggers this
_ledStrip.LightModes.ChangeMode(CbMode.SelectedIndex);
}
private void MainWindow_OnClosing(object sender, CancelEventArgs e)
{
// Trigger disconnect and wait for success - this doesn't work (explained below in code comments)
_ledStrip.LightModes.Disconnect().Wait();
}
Класс световых режимов:
private Task _modeTask;
private CancellationTokenSource _cancellationToken = new CancellationTokenSource();
// This is being triggered by change mode
internal async void ChangeMode(int mode)
{
// It waits for current loop to finish
await StopTask();
switch (mode)
{
case (int)Modes.Static:
// Then assigns new one
_modeTask = Static(_cancellationToken.Token);
break;
case (int)Modes.Breath:
_modeTask = Breath(_cancellationToken.Token);
break;
}
}
internal async Task StopTask()
{
if (_modeTask == null)
return;
// Set cancellation token to cancel
_cancellationToken.Cancel();
try
{
// and wait for task to finish. This works if triggered by user interaction BUT this is where it gets stuck when called by Disconnect() method (below). It awaits here forever
await _modeTask;
}
catch (TaskCanceledException ex)
{
Console.WriteLine(ex.Message);
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// After sucessful await create new cts
_cancellationToken.Dispose();
_cancellationToken = new CancellationTokenSource();
}
}
// Example of LED effect loop
internal async Task Static(CancellationToken cancellationToken)
{
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
_ledStrip.FillLedsWithColor();
// Wait for strip to light up
await LightLeds();
// Delay before next loop round
await Task.Delay(15, cancellationToken);
}
}
// This is being called by window onclosing
internal async Task Disconnect()
{
//Stop current task and close serial connection. _device is serial
await StopTask();
Application.Current.Dispatcher.Invoke(() =>
{
if (_device.IsOpen())
{
_device.Clear();
_device.Close();
}
});
}
// Method for sending LED information to Arduino
internal async Task LightLeds()
{
if (!_device.IsOpen())
return;
await Task.Run(() =>
{
for (int i = 0; i < StaticValues.NumLeds; i++)
{
_device.Send((byte)i, _ledStrip.Leds[i].LedColor.R, _ledStrip.Leds[i].LedColor.G, _ledStrip.Leds[i].LedColor.B);
}
_device.LightUp();
});
}
Я начинающий с Задачами, и я почти уверен, что я не использую их должным образом (некоторые из них, безусловно, не нужны, но я этого не знаю), и, возможно, это причина того, что это не работает. Я попытался выполнить поиск и нашел много примеров использования задач, но до сих пор не очень хорошо понимаю.
Спасибо!