使用control.begininvoke后,UI仍然没有响应

时间:2022-08-27 21:20:25

i've made a C# winforms application. Now i have a form which has lots of buttons, which call huge number crunching functions whose output i update in a textbox. I call the textbox.begininvoke() method to which i pass a delegate to the function which updates the text in the textbox, however when the text is huge, the form is non responsive as i can't click on the cancel button. Isn't there any way so that the whole form remains responsive and as well the update too keeps happening. I have to show the data to the user as it is coming, i can't buffer the whole thing and show in the end. I also tried to implement my own buffer and show data at particular intervals which works great for small amount of text, but in huge amount the UI just doesn't respond. any help? Thanks

我做了一个C#winforms应用程序。现在我有一个有很多按钮的表单,它调用了大量的数字运算函数,其输出我在文本框中更新。我调用textbox.begininvoke()方法,我将委托传递给更新文本框中文本的函数,但是当文本很大时,表单没有响应,因为我无法单击取消按钮。没有任何办法可以使整个表格保持响应,并且更新也会不断发生。我必须向用户显示数据,因为它即将到来,我无法缓冲整个事情并最终显示。我还尝试实现自己的缓冲区并以特定的时间间隔显示数据,这对于少量文本很有用,但是大量的UI只是没有响应。任何帮助?谢谢

updating question as some confusions are arising

随着一些混乱的出现而更新问题

  • i've called the number crunching function on a separate thread.
  • 我在一个单独的线程上调用了数字运算功能。

  • that number crunching function calls the control.begininvoke function whenever data arrives to update the textbox
  • 只要数据到达以更新文本框,该数字运算函数就会调用control.begininvoke函数

  • MY UI gets to be displayed and i see the output coming, but when the data is huge, i can't do any other activity though i can still see the UI
  • 我的UI得到显示,我看到输出即将到来,但是当数据很大时,我无法做任何其他活动,虽然我仍然可以看到UI

3 个解决方案

#1


Calling BeginInvoke (or Invoke) will not buy you anything unless the number crunching function is running on another thread than the UI thread.

调用BeginInvoke(或Invoke)将不会为您买任何东西,除非数字运算函数在除UI线程之外的另一个线程上运行。

Consider the following code:

请考虑以下代码:

private void HardWork(object state)
{
    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(500);
        SetText(i.ToString());
    }
}

private void SetText(string text)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action<string>(SetText), text);
    }
    else
    {
        textBox1.Text = text;
    }
}
private void Button_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(HardWork);            
}

The Button_Click method will start executing the method HardWork on a separate thread. HardWork will do some processing (simulated by the Thread.Sleep call) and then call a method to display some progress. Inside this method, we need to check whether we are on the UI thread or not. If we are not, we invoke the same method using Invoke (or BeginInvoke) in order to force it to execute on the UI thread.

Button_Click方法将在单独的线程上开始执行HardWork方法。 HardWork将进行一些处理(通过Thread.Sleep调用模拟),然后调用方法来显示一些进度。在这个方法中,我们需要检查我们是否在UI线程上。如果我们不是,我们使用Invoke(或BeginInvoke)调用相同的方法,以强制它在UI线程上执行。

Update: if the amount of data emitted from the number crunching method is very large, this might of course have a negative impact on the UI responsiveness. If you for instance accumulate a large amount of text in your threaded method and emit that text on every update, that will be slower than just emitting what has changed since the last update. The same goes for the text box; calling TextBox.AppendText with just the new text will be faster than repedetly assigning the TextBox.Text property.

更新:如果从数字运算方法发出的数据量非常大,这当然可能会对UI响应性产生负面影响。例如,如果您在线程方法中累积了大量文本并在每次更新时发出该文本,那么这将比发布自上次更新后发生的更改更慢。文本框也是如此;仅使用新文本调用TextBox.AppendText将比重复分配TextBox.Text属性更快。

It's hard to give more detailed ideas on how to solve your particular problem since we have not see what your code actually does.

由于我们没有看到您的代码实际上做了什么,因此很难提供有关如何解决您的特定问题的更详细的想法。

#2


You got it backwards.

你倒退了。

BeginInvoke is what you should use to update the UI. It does not spawn a new thread, as you seem to believe.

您应该使用BeginInvoke来更新UI。它似乎不会产生一个新的线程,你似乎相信。

BeginInvoke is simply "Execute the following within the thread that the control was originally created in", which is your UI thread.

BeginInvoke只是“在最初创建控件的线程中执行以下内容”,这是您的UI线程。

BeginInvoke is therefore what you should use in your number crunching thread to post back updates into the UI.

因此,您应该在数字运算线程中使用BeginInvoke将更新回发到UI中。

Hope this helps

希望这可以帮助

#3


Have the function that updates the text box do it piece by piece and call DoEvents between each update. That is, break up the string and ...

具有更新文本框的功能可以逐个执行,并在每次更新之间调用DoEvents。也就是说,分解字符串并......

update piece 1
DoEvents
update piece 2
DoEvents
...
update piece n

#1


Calling BeginInvoke (or Invoke) will not buy you anything unless the number crunching function is running on another thread than the UI thread.

调用BeginInvoke(或Invoke)将不会为您买任何东西,除非数字运算函数在除UI线程之外的另一个线程上运行。

Consider the following code:

请考虑以下代码:

private void HardWork(object state)
{
    for (int i = 0; i < 10; i++)
    {
        Thread.Sleep(500);
        SetText(i.ToString());
    }
}

private void SetText(string text)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action<string>(SetText), text);
    }
    else
    {
        textBox1.Text = text;
    }
}
private void Button_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(HardWork);            
}

The Button_Click method will start executing the method HardWork on a separate thread. HardWork will do some processing (simulated by the Thread.Sleep call) and then call a method to display some progress. Inside this method, we need to check whether we are on the UI thread or not. If we are not, we invoke the same method using Invoke (or BeginInvoke) in order to force it to execute on the UI thread.

Button_Click方法将在单独的线程上开始执行HardWork方法。 HardWork将进行一些处理(通过Thread.Sleep调用模拟),然后调用方法来显示一些进度。在这个方法中,我们需要检查我们是否在UI线程上。如果我们不是,我们使用Invoke(或BeginInvoke)调用相同的方法,以强制它在UI线程上执行。

Update: if the amount of data emitted from the number crunching method is very large, this might of course have a negative impact on the UI responsiveness. If you for instance accumulate a large amount of text in your threaded method and emit that text on every update, that will be slower than just emitting what has changed since the last update. The same goes for the text box; calling TextBox.AppendText with just the new text will be faster than repedetly assigning the TextBox.Text property.

更新:如果从数字运算方法发出的数据量非常大,这当然可能会对UI响应性产生负面影响。例如,如果您在线程方法中累积了大量文本并在每次更新时发出该文本,那么这将比发布自上次更新后发生的更改更慢。文本框也是如此;仅使用新文本调用TextBox.AppendText将比重复分配TextBox.Text属性更快。

It's hard to give more detailed ideas on how to solve your particular problem since we have not see what your code actually does.

由于我们没有看到您的代码实际上做了什么,因此很难提供有关如何解决您的特定问题的更详细的想法。

#2


You got it backwards.

你倒退了。

BeginInvoke is what you should use to update the UI. It does not spawn a new thread, as you seem to believe.

您应该使用BeginInvoke来更新UI。它似乎不会产生一个新的线程,你似乎相信。

BeginInvoke is simply "Execute the following within the thread that the control was originally created in", which is your UI thread.

BeginInvoke只是“在最初创建控件的线程中执行以下内容”,这是您的UI线程。

BeginInvoke is therefore what you should use in your number crunching thread to post back updates into the UI.

因此,您应该在数字运算线程中使用BeginInvoke将更新回发到UI中。

Hope this helps

希望这可以帮助

#3


Have the function that updates the text box do it piece by piece and call DoEvents between each update. That is, break up the string and ...

具有更新文本框的功能可以逐个执行,并在每次更新之间调用DoEvents。也就是说,分解字符串并......

update piece 1
DoEvents
update piece 2
DoEvents
...
update piece n