Я создал приложение для перепрошивки устройства по интерфейсу UART
Хочу добавить необязательное, но желаемое взаимодействие с программой:
Остановка работы потока по нажатию на кнопку "Остановить выполнение".
Программа работает следующим образом:
private void Execute_Commands_Button_Click(object sender, EventArgs e)
// Нажатие на кнопку "Выполнить команды"
{
// Очистить данные
Clear_Data();
// Если нет ошибок в полях
if (Check_All_Fields())
{
// Если есть соединение с портом
if (Check_Port())
{
// Если параметры работы с портом установлены успешно
if (Set_Port_Settings())
{
// Обновить данные Hex- файла
Refresh_Hex_File_Data();
// Если устройство не синхронизировано
if (!Is_Synchronised)
{
// Поток для синхронизации
Thread Sync_Thread;
// Поток для синхронизации
Sync_Thread = new Thread(delegate()
{
// Выключить элементы управления
Set_Enable(false);
// Попытаться синхронизировать
Try_To_Synchronise_Device(Convert.ToInt32(
This_Common.Read_From_Registry(This_Common.Key_Sync_Attempts)));
// Включить элементы управления
Set_Enable(true);
});
// Записываем поток как текущий
Active_Thread = Sync_Thread;
// Запуск потока
Sync_Thread.Start();
// Ожидание завершения работы потока
Sync_Thread.Join();
}
// Если устройство синхронизировано
if (Is_Synchronised)
{
// Обновить список команд
Refresh_Commands();
// Попытаться послать команды на порт
Try_To_Send_Commands();
}
// Если устройство не синхронизировано
else
{
// Вывести ошибку
This_Common.Show_Error_Message("Не удалось синхронизироваться с устройством!");
}
// Закрыть порт
Selected_Port.Close();
}
}
}
}
В функции void Set_Enable(bool) Все элементы управления становятся неактивными и включается только кнопка "Остановить выполнение".
при нажатии на эту кнопку активный поток закрывается: Active_Thread.Abort()
Проблема заключается в следующем: после ожидания выполнения группы методов в отдельном потоке я теряю возможность обрабатывать нажатия на кнопку "Остановить выполнение". Как это можно исправить?
Вариант с Task не сработал. Код следующий:
// Обработчик запроса отмены задачи
CancellationTokenSource Source = new CancellationTokenSource();
// Переменная отключения выполнения задачи
CancellationToken Cancel_Token;
// Задача "Синхронизировать"
Task Sync_Task;
// Задать задачу
Sync_Task = new Task(delegate()
{
// Попытаться синхронизироваться
Try_To_Synchronise_Device(Convert.ToInt32(This_Common.Read_From_Registry(This_Common.Key_Sync_Attempts)));
}, Cancel_Token);
// Запуск задачи
Sync_Task.Start();
// Ожидаем выполнение задачи
Source.Wait();
При клике на кнопку "Остановить выполнение": Source.Cancel();
Ответ
Я тоже наклепал пример попроще.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//источник токена отмены
CancellationTokenSource _tokenSource;
//Запуск
private async void _buttonStart_Click(object sender, EventArgs e)
{
//через него будем оповещать о ходе выполнения задачи
Progress
//готовим токен отмены
_tokenSource = new CancellationTokenSource();
CancellationToken cancelToken = _tokenSource.Token;
//запускаем долгую задачу
try
{
this._labelOutput.Text = "Начинаем...";
//обратите внимание на передачу токена отмены, и экземпл. прогресса
this._labelOutput.Text = await Task.Run(() => DoSomething(cancelToken, progess), cancelToken);
}
catch (OperationCanceledException)
{
this._labelOutput.Text = "Задача отменена.";
}
catch (Exception ex)
{
this._labelOutput.Text = $"В задаче произошла ошибка: {ex.Message}";
}
}
//Отмена
private void _buttonCancel_Click(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
//Эта самая долгая задача, обратите внимание на тип параметра progess он IProgress
//задержка между этапами 1 сек.
cancelToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(1));
//здесь будет выброшено исключение в случае нажатия на кнопку отмены
cancelToken.ThrowIfCancellationRequested();
}
return "Готово!";
}
}
Комментариев нет:
Отправить комментарий