3

My code :

void Method(){
Task T = Task.Factory.StartNew(() =>
{
    for (int i=0;i<count;i++)
    {
        textBox1.Text += "x";
        Thread.Sleep(500);
    }
});
T.Wait();
}

I want to this task wait until everything ends and then exists the method and the main thread resume its work... But i get AggregateException was unhandled Error on T.Wait();

What's wrong with this ?

Al00X
  • 1,492
  • 1
  • 12
  • 17
  • 3
    An `AggregateException` contains inner exceptions. The inner exception here already tells you *exactly* what's wrong. –  Dec 31 '16 at 10:18
  • An unhandled exception of type 'SystemAggregateException' occurred in mscorlib.dll Additional information: One or more errors occurred. – Al00X Dec 31 '16 at 10:20
  • 3
    Yes, that's the exception itself, and the *inner* exceptions will tell you what's wrong. I suspect it's because you're accessing the UI on a non-UI thread. – Jon Skeet Dec 31 '16 at 10:21
  • 1
    Okay, let me shift the emphasis. The *inner exception* here already tells you exactly what's wrong. You're not looking at the inner exception. –  Dec 31 '16 at 10:21
  • 1
    {"Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on."} Sorry i didn't saw you said innerexception – Al00X Dec 31 '16 at 10:21
  • @Al00X Right. Note though: the normal way to let that work is to get the child thread to notify the main thread that it has work to do. You cannot make that work as long as the main thread is blocked and waiting for your child thread to finish. And it's not clear what the desired behaviour of your code is, so it's not clear how to write it instead. If you can make an attempt to fix it to do what you want, then if you get stuck, that could make for a better question to ask here. –  Dec 31 '16 at 10:25
  • My main thread **Should** Wait for this task and update the UI until the end of the task... what should i do ? using thread or backgroundworker ?? – Al00X Dec 31 '16 at 10:31
  • @Al00X If you want the UI to be functional, if you want to reliably *see* your updates, that requires the main thread to not be busy. There's a lot that .NET does for you behind the scenes on the main thread, and if you suppress that by blocking the main thread, things break. That's why the main thread cannot simply wait for this task. What's the reason you want to wait for this task? If it's so that the user can do nothing else meanwhile, what you can do instead is disable the controls on your form. If it's to do something when the thread is done, there's no need to block, just call it after. –  Dec 31 '16 at 10:59

3 Answers3

3

You will have to check whether the current execution is happening on the UI thread or not while updating the UI control. If that is not the case then do as shown below:

void Method(){
Task T = Task.Factory.StartNew(() =>
{
    for (int i=0;i<count;i++)
    {
        UpdateUi functionToUpdateUi = UpdateTextBoxControl;
        if (textBox1.InvokeRequired)
            textBox1.BeginInvoke(functionToUpdateUi);

        //textBox1.Text += "x"; this is non-GUI thread. You can't update GUI controls like this
        Thread.Sleep(500);
    }
});
T.Wait();
}

//declaration of delegate signature
delegate void UpdateUi();    

//this is a new method which you will create separately
private void UpdateTextBoxControl()
{
    //this method gets executed on GUI thread so it safe
    textBox1.Text = "Changed the text from background thread.";
}
RBT
  • 24,161
  • 21
  • 159
  • 240
1

You can catch the AggregateException and see what's gone wrong for all tasks that ran.

catch (AggregateException err)
{
    foreach (var e in err.InnerExceptions)
    {
        exception = err.InnerException;
    }
}
Asken
  • 7,679
  • 10
  • 45
  • 77
1

I would advice you to not start messing with starting tasks yourself. You can rewrite it this way

int count = 10;
async Task MethodAsyncs()
{
    for (int i = 0; i < count; i++)
    {
        textBox1.Text += "x";
        await Task.Delay(500);
    }
}
Tvde1
  • 1,246
  • 3
  • 21
  • 41
Dave Smits
  • 1,871
  • 14
  • 22
  • This worked but my main thread is not waiting for the task to finish... How to wait for it ? – Al00X Dec 31 '16 at 11:21
  • you should call this method by using await in front of it. The method that is calling it should have the async modifier – Dave Smits Dec 31 '16 at 16:04