Reputation: 33
I'm rebuilding one of my WinForms applications in WPF, and I've encountered an issue with threading. I start the thread from a method in my UI class, such as a button click:
workerThread = new Thread(() => Engine.Start());
workerThread.Start();
The workerThread method follows this kind of general format:
static class Engine
{
public static bool RunThread = true;
public static void Start()
{
while (RunThread)
{
// Do Stuff
}
}
}
This is a loop that will constantly output data to a USB device. I only ever want this thread to end when I change my RunThread variable to false from elsewhere in the program. The issue lies in waiting for the thread to finish. If I close my MainWindow, the thread will continue until it tries to start a new loop and then quits, which means it might make calls to portions of the MainWindow that don't exist any more since it's being destroyed. If I run workerThread.Join(); the entire application freezes and becomes completely unresponsive.
Previously, I had set up something of this sort in my FormClosing method, to ensure it would wait for the thread to quit before moving on to other cleanup operations:
if (workerThread != null) {
// Ask the thread to destroy itself
Engine.RunThread = false;
// If the thread is busy, wait for it to end
while (workerThread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
};
It's not the most graceful, but in WinForms it made sure the thread exited cleanly and then moved on. Trying something like this in WPF, however, just causes it to get stuck in the while loop; as I think it's blocking the thread from continuing and closing itself. Of course, I had to remove the Application.DoEvents(); since that doesn't exist in WPF.
My suspicion is that I'm not creating this thread using the best techniques available in WPF, so my question is this: What's the best way to launch this thread so that I can safely exit it (and potentially start a new instance) later?
Upvotes: 3
Views: 726
Reputation: 12846
As other people in the comments have noted, use a Task
instead of a Thread
.
Task workerTask = Task.Run(() => Engine.Start());
To make the UI wait with closing until the Task
finished executing, handle the Closing
event of the Window
and wait until workerTask
finished.
private async void NavigationWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
await workerTask;
}
Upvotes: 1