Вот два способа рефакторинга кода, чтобы избежать использования уродливой техники this.Invoke((MethodInvoker)delegate
. Если USB-считыватель имеет свободный поток, вы можете вызывать каждый из его методов в разных ThreadPool
потоках, например:
async Task LoopAsync(CancellationToken ct)
{
await Task.Run(() => InitUSBReader(), ct);
while (!ct.IsCancellationRequested)
{
int[] data = await Task.Run(() => ReadUSB(), ct);
lbOut1.Text = data[0].ToString();
lbOut2.Text = data[1].ToString();
lbOut3.Text = data[2].ToString();
await Task.Delay(100);
}
await Task.Run(() => CleanupUSBReader(), ct);
}
Но если USB-считыватель требует привязки потоков, то описанный выше метод не будет работать . Чтобы заставить его работать в одном потоке, вы можете использовать описанную ниже технику, которая также предлагает преимущество отделения кода пользовательского интерфейса от кода чтения USB:
Task LoopAsync(IProgress<int[]> progress, CancellationToken ct)
{
return Task.Factory.StartNew(() =>
{
InitUSBReader();
while (!ct.IsCancellationRequested)
{
int[] data = ReadUSB();
progress.Report(data);
Thread.Sleep(100);
}
CleanupUSBReader();
}, TaskCreationOptions.LongRunning);
}
... и запускать задачу, подобную этой :
m_USBReaderTask = LoopAsync(new Progress<int[]>(data =>
{
lbOut1.Text = data[0].ToString();
lbOut2.Text = data[1].ToString();
lbOut3.Text = data[2].ToString();
}), m_CancellationSource.Token);
Класс Progress
обычно используется для отчета о прогрессе, но он может сообщать любые данные.
Для очистки, когда форма закрывается, вы можете обработать событие FormClosing
следующим образом:
private async void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (!m_USBReaderTask.IsCompleted)
{
e.Cancel = true;
this.Enabled = false;
m_CancellationSource.Cancel();
await m_USBReaderTask;
await Task.Yield(); // Ensure the asynchronous completion before Close
this.Close();
}
}