简体   繁体   English

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

[英]How can I use background worker(or any other solution) to stop freezing my GUI?

I'm trying to fix a problem in my Winforms application where the GUI tends to lock up. 我正在尝试解决Winforms应用程序中GUI倾向于锁定的问题。

Current Solution: The application is written to read from a serial port and write to a rich textbox in the GUI. 当前解决方案:编写该应用程序以从串行端口读取并写入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). 如果是,如何调整我的解决方案以适应此更改?(我知道后台工作程序无法访问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. 免责声明 :我对Winforms和C#还是比较陌生。 So any advice would be appreciated! 因此,任何建议将不胜感激!

You can use several approaches here: 您可以在此处使用几种方法:

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. 我建议使用async/await方法,因为MS已经完成了确保所有内容保持同步的艰苦工作,但是您可以根据自己的应用来决定所需的内容。

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 为了确保您可以访问UI线程,您必须使用Invoke方法: 从另一个线程更新GUI-SO

An example of rolling your own Thread would be the following: 滚动自己的Thread的示例如下:

  • Putting all your serial handing code in it's own object/class 将所有串行处理代码放入自己的对象/类中
  • Instantiate object from the Main From start the receiving method on it's own thread 从Main实例化对象从它自己的线程上开始接收方法
  • When data is received, raise an event back to the main thread 收到数据后,将事件引发回主线程

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 如果您在while循环中所做的额外工作不重要,则可能需要移动

await Task.Factory.StartNew(() => { });

to outside the while loop. while循环之外。 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. 目标是不要太严重地束缚Task ,因为允许运行Task的线程数量是有限的。

An alternate method of calling the Invoke would be the following: 调用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.
}

You could then simply call writeToTextBox from wherever, and it would handle the invoke itself. 然后,您可以从任何地方简单地调用writeToTextBox ,它将处理调用本身。

to avoid recoding all your project, you can try to use Application.DoEvents() . 为了避免重新编码所有项目,可以尝试使用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! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我将如何使用Background Worker来使GUI响应? - How would I use Background Worker to get my GUI to respond? 如何从我的解决方案中的其他项目中使用我的Web Api项目? - How can I use my Web Api project from other projects inside my solution? 如何将我的代码适合后台工作人员? - How can I fit my code into a Background Worker? 如何在解决方案中使用数据库 - How can I use a database into my solution 停止其他项目的后台工作者 - Stop the background worker from other project 如何在 WPF 中停止后台工作人员? - How to stop background worker in WPF? Backgroundworker冻结了我的GUI - Backgroundworker is freezing my GUI 背景工作者仍然冻结ui - Background worker still freezing ui 更改页面以及将应用程序移至后台时如何停止Device.StartTimer()? 和正确使用MessagingCenter - How can I stop a Device.StartTimer () when I change the page and when my app is moved to the background? and correct use of MessagingCenter 将 Web 应用项目添加到我的解决方案中,并且解决方案中的其他项目已经使用 .net 框架,我可以将 .net 核心用于新项目吗? - adding a web app project to my solution, and the other projects in the solution already use .net framework, can I use .net core for the new project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM