如何使用后台工作程序(或任何其他解决方案)来停止冻结我的GUI?

时间:2014-04-05 19:47:25

标签: c# winforms user-interface

我正在尝试修复我的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#都比较陌生。所以任何建议都将不胜感激!

2 个答案:

答案 0 :(得分:3)

您可以在此处使用多种方法:

我建议使用async/await方法,因为MS已经完成了确保所有内容保持同步的艰苦工作,但您可以根据应用决定您想要的内容。

要确保您可以访问UI线程,您必须使用Invoke方法:Updating the GUI from another thread - SO

滚动自己的Thread的示例如下:

  • 将所有序列处理代码放入其自己的对象/类
  • 从Main开始实例化对象从它自己的线程开始接收方法
  • 收到数据后,将事件提升回主线程

为避免锁定用户界面,您可以执行以下操作:

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,它将处理调用本身。

答案 1 :(得分:0)

为避免重新编码您的所有项目,您可以尝试使用Application.DoEvents()

void writeToTextBox(inputdata)
{
    /*your code */
     Application.DoEvents();
}

您可以看到there方法的说明和一些示例。希望这有帮助!