tags:

views:

860

answers:

3

Hi 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

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
  • 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
+6  A: 

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 is simply "Execute the following within the thread that the control was originally created in", which is your UI thread.

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

Hope this helps

Tormod
I've created a separate thread on which the number crunching function is called, and that in turns calls the begininvoke method on the control to post updates.Isn't that how it must be done?
Anirudh Goel
A: 

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 ...

update piece 1
DoEvents
update piece 2
DoEvents
...
update piece n
JP Alioto
+7  A: 

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

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.

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.

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.

Fredrik Mörk
i exactly have done the work in this way, but imagine what will happen to the ui if i equals 10000000 (a huge number). The UI gets non responsive and i don't get to click on other items.
Anirudh Goel
Nice. I very much liked the SetText construct. Is this from some online cookbook resource that I should know about? Thanks.
Tormod
Nope. I believe this is the guideline for UI programming with multiple threads. You put a defensive check to see if the method is being called on the UI thread - if not you transition to the UI Thread before executing any UI specific code.
Gishu
http://msdn.microsoft.com/en-us/library/ms171728%28VS.80%29.aspx
Gishu
@Tormod: as @Gishu mentions this is how multithreaded UI programming often looks like. If you google for "InvokeRequired" you will find tutorials.
Fredrik Mörk
@fredrik: can you please read my comment and tell what more can be done to avoid such issue?
Anirudh Goel
@Anirudh: I just updated my answer with some discussion on that.
Fredrik Mörk