0

I have the following issue with my simplified code (WPF) below:

System.InvalidOperationException' in PresentationCore.dll The calling thread must be STA, because many UI components require this

Would be so kind to help me to correct my code.

void CrearBtnNews()     
{
       KinectTileButton botontest = new KinectTileButton
       {
           Style = FindResource("KinectTileButtonStyle1") as Style,
           Content = "WeB",
           Height = 265,
           Width = 450,
           Background = null,
           BorderBrush = null
       };

       botontest.Click +=
       async (o, args) =>
      {
        await Task.Run(()=> BrowserAsync());
      };
}

private void BrowserAsync()
{
    Grid gridx = new Grid();//////// ERROR  in this line ///////////////
    System.Threading.Thread.Sleep(8000);
    MessageBox.Show("working 8 seg");
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
emmtlm
  • 1
  • 1

2 Answers2

2

All UI-related things must be done in the main UI thread. You are trying to create an UI element in a background thread, which is a no-go.

If you want to do some long calculations etc. in the background, you should do only that, and then return the data to the main thread and create the UI controls there.

Something like this: (ResultStruct is madeup)

button.Click += async(o,args) =>
{
    ResultStruct data = await Task.Run(() => Browser());

    Grid gridx = new Grid();
    // set the data to the grid
};

private ResultStruct Browser()
{
    // calculations, working ...
    return data;
}

Also, method BrowserAsync is not actually async, you are just calling it in an async task, so I renamed it to just Browser.

GregorMohorko
  • 2,739
  • 2
  • 22
  • 33
  • As the Browser method source is available, it would be preferred to use `TaskCompletionSource` instead of wrapping a Synchronous method in a `Task.Run` wrapper – Mrinal Kamboj Jan 14 '17 at 17:43
  • 1
    Crux here is this statement, which OP needs to understand and resolve, You are trying to create an UI element in a background thread, which is a no-go, +1 for that. – Mrinal Kamboj Jan 14 '17 at 17:49
  • I agree about the `TaskCompletionSource`, but regarding that obviously the OP doesn't completely understand the whole concept, I tried to edit his code as little as possible. – GregorMohorko Jan 14 '17 at 22:32
0

There's no need to wrap the entire method in Task.Run. Instead, you should only be wrapping 'the work' in Task.Run, and handle the creation of UI components on the UI thread. Though, if the creation of components is a lot, you can also wrap that in an async called (as shown in the example).

Note: The reason why you are getting the error is because you are trying to create a UI component (the Grid) on a separate thread. All UI specific stuff must be created on a Dispatcher thread.

 void CrearBtnNews()
 {
    KinectTileButton botontest = new KinectTileButton
    {
        Style = FindResource("KinectTileButtonStyle1") as Style,
        Content = "WeB",
        Height = 265,
        Width = 450,
        Background = null,
        BorderBrush = null
    };

   botontest.Click += async (o, args) =>
   {
      Grid gridx = new Grid();

      await BrowserAsync();

      MessageBox.Show("working 8 seg");
   };
 }

private async Task BrowserAsync()
{
    // Do work here
    //
    await Task.Run(() => 
    {
        System.Threading.Thread.Sleep(8000);
    });
}
d.moncada
  • 16,900
  • 5
  • 53
  • 82
  • await Application.Current.Dispatcher.InvokeAsync((Action)() => this line show sintax error. Sorry – emmtlm Jan 14 '17 at 17:48
  • Looks like a fairly round about solution for a much simple question, why not `await Task.Delay(8000)`, Also Grid components can be created on either side of await call, this needn't be done in the background as suggested – Mrinal Kamboj Jan 14 '17 at 17:53
  • @emmtlm sounds like you are using a different framework version. I'll update. – d.moncada Jan 14 '17 at 17:59
  • @MrinalKamboj I assumed Sleep was just an example to simulate work, nothing more. If it is indeed an actual Sleep call, yes, Delay will work. I also assumed Grid creation included more UI component than just that. The UI thread will lock up if there's a lot more components that need to be created due to load/rendering. – d.moncada Jan 14 '17 at 18:01
  • Sleep I understand, your view, also for the grid loading and rendering is taking lot of time, then this operation can be taken into background as suggested and this is similar to doing it in non blocking way W/o using threads – Mrinal Kamboj Jan 14 '17 at 18:15
  • Yeah of course. there's just way too many variables and missing information in this question I believe... they claim this is a 'simplified' solution, so I'm assuming the actual implementation is a lot more complex. – d.moncada Jan 14 '17 at 18:17
  • @emmtlm see update. I made it very simple, assuming that your Browser method is actually doing work rather than just sleeping. – d.moncada Jan 14 '17 at 18:18