I'm trying to fix a problem in my Winforms application where the GUI tends to lock up.
Current Solution: The application is written to read from a serial port and write to a rich textbox in the GUI. Now, the response can be a single response or continuous streaming at high speed, based on the input .
As of now I'm updating the textbox with content as and when I receive it from the device,ie. with an event handler that triggers when data is received from the serial port.
Is background worker the only solution to the problem? If yes, how do I restructure my solution to accomodate this change?(I understand the background worker cannot access the GUI). If not, are there any better solutions?
EDIT for Code : Here is the general code flow
//Function triggered when data received from serial port
private void DataReceived(object sender, EventArgs e)
{
while (serialPort1.BytesToRead > 0 && serialPort1.IsOpen)
{
//calls to several processing functions
//which then call a function writetoTextBox and pass the data to write
}
}
//write to textbox
void writeToTextBox(inputdata)
{
// write to textbox.
//If user has asked to write to file. Open a file dialog to get file name and write to it
// as well. As of now when the data rate is high, this part doesnt get the time to respond
//as the GUI locks up the thread
}
Disclaimer : I'm relatively new to winforms and C# as such. So any advice would be appreciated!
You can use several approaches here:
BackroundWorker
(which you suggested) Task
object and async/await
: Asynchronous Programming with Async and Await - MSDN Thread
: Thread Class - MSDN I recommend using the async/await
method since MS already did the hard work of making sure everything stays synchronized, but you can decide what you want based on your app.
To make sure that you can access the UI thread, you'll have to use the Invoke
method: Updating the GUI from another thread - SO
An example of rolling your own Thread
would be the following:
To avoid locking the UI, you could do something like the following:
private delegate void writeToTextBoxDelegate(List a, List b);
private async void DataReceived(object sender, EventArgs e)
{
while (serialPort1.BytesToRead > 0 && serialPort1.IsOpen)
{
await Task.Factory.StartNew(() =>
{
// Do whatever work you want to do here.
// When you're all done, call the following line.
textBox.Invoke(
new writeToTextBoxDelegate(writeToTextBox),
new object[] { a, b }
);
});
}
}
If the extra work you're doing inside the while
loop is not significant, you may want to move the
await Task.Factory.StartNew(() => { });
to outside the while
loop. The goal is to not tie up the Task
too badly, since the number of threads which are allowed to run Task
s are limited.
An alternate method of calling the Invoke
would be the following:
private delegate void writeToTextBoxDelegate(List a, List b);
private void writeToTextBox(List a, List b)
{
if (textBox.InvokeRequired)
{
textBox.Invoke(new writeToTextBoxDelegate(writeToTextBox),
new object[] { a, b });
return;
}
// Your custom write-to-textbox code here.
}
You could then simply call writeToTextBox
from wherever, and it would handle the invoke itself.
to avoid recoding all your project, you can try to use Application.DoEvents()
.
void writeToTextBox(inputdata)
{
/*your code */
Application.DoEvents();
}
You can see there the description of the method and a little example. Hope this helps!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.