如何使用后台工作程序(或任何其他解决方案)来停止冻结我的 GUI
本文关键字:冻结 GUI 我的 解决方案 其他 后台 何使用 工作程序 任何 | 更新日期: 2023-09-27 17:56:45
我正在尝试修复 Winforms 应用程序中 GUI 趋于锁定的问题。
当前解决方案:应用程序被写入从串行端口读取并写入 GUI 中的富文本框。现在,响应可以是单个响应,也可以是基于输入的高速连续流式传输。
截至目前,我正在使用从设备接收内容时的内容更新文本框,即使用从串行端口接收数据时触发的事件处理程序。
后台工作者是解决问题的唯一解决方案吗?如果是,如何重构解决方案以适应此更改?(我知道后台工作者无法访问 GUI)。如果没有,有没有更好的解决方案?
编辑代码:这是常规代码流
//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
}
免责声明:我对winforms和C#本身相对较新。因此,任何建议将不胜感激!
您可以在此处使用多种方法:
BackroundWorker
(您建议的)Task
对象和async/await
:异步和等待的异步编程 - MSDN- 基于
Thread
滚动您自己的后台辅助角色:线程类 - MSDN
我建议使用 async/await
方法,因为 MS 已经努力确保一切保持同步,但您可以根据您的应用程序决定您想要什么。
若要确保可以访问 UI 线程,必须使用 Invoke
方法:从另一个线程更新 GUI - SO
滚动自己的Thread
的示例如下:
- 将所有串行处理代码放在它自己的对象/类中 从
- 主线程实例化对象 从它自己的线程上启动接收方法
- 收到数据后,将事件引发回主线程
若要避免锁定 UI,可以执行以下操作:
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 }
);
});
}
}
如果您在while
循环中所做的额外工作并不重要,您可能需要移动
await Task.Factory.StartNew(() => { });
到while
循环之外。目标是不要太严重地占用Task
,因为允许运行Task
的线程数量是有限的。
调用Invoke
的另一种方法是:
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.
}
然后,您可以简单地从任何地方调用writeToTextBox
,它将处理调用本身。
为了避免重新编码所有项目,您可以尝试使用 Application.DoEvents()
.
void writeToTextBox(inputdata)
{
/*your code */
Application.DoEvents();
}
您可以在那里看到该方法的描述和一个小示例。希望这有帮助!