I am writing a WinForms application. I will have 2 threads, a UI thread and Operation thread. The UI thread produces Control events, and I want the Operation thread to consume them. The Operation thread is automated and will run Tasks for hardware control concurrently with the consumption of new events. Control events are but not limited to Start/Stop the automation
I am using BackgroundWorker because my Operation thread will also update the UI in the MVP architecture style.
Example of what I'd like, simplified for brevity.
public class UI : Form
{
Operation _operation;
BackgroundWorker _operationBackgroundWorker;
public UI_Load(object sender, EventArgs e)
{
_operationBackgroundWorker.RunWorkerAsync();
}
private void operationBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
_operation.DoWorkAsync(worker);
}
private void operationBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Only executed if something fails.
}
private void btnStart_Click(object sender, EventArgs e)
{
/* Much later in the Application lifecycle,
* somehow trigger an event on operation thread
* to begin operation.
*/
}
}
/* The operation thread. This code must run as long as the
* application is open, or until a critical error occurs.
*/
public class Operation
{
public async Task DoWorkAsync(BackgroundWorker worker)
{
// Live as long as the application and consume
// user control events fired by UI thread.
while (!worker.CancellationPending)
{
/* Make thread "sleep" until an event is triggered.
* It should be possible to fire an event while another
* operation is in progress such as stop or manual
* override (a Queue). Operation thread also uses a
* BackgroundWorker to execute hardware commands
* to not block Event queue execution.
*/
// Example operation
foreach (var event in eventQueue)
{
switch (event)
{
case Start:
// Run concurrently, for loop moves on
// to next event.
_automationWorker.RunWorkAsync();
// Uses Control.BeginInvoke() on controls
// to not block itself.
ControlView.ChangeControlToPause();
case Pause:
PauseAutomationWorker();
ControlView.ChangeControlToResume();
case Stop:
StopAutomationWorker();
ControlView.ChangeControlToStopped();
}
}
}
}
}
I have previously written my application with async/await and no separate Operation thread. That did not work because it made the codebase difficult to maintain and (I failed to find the bug) sometimes make the UI hang or not respond to new control inputs. Therefore I am looking for a cleaner alternative.