Error creating a new element - WPF Async / Await

2

When I run my code I get the following error:

  

System.InvalidOperationException 'in PresentationCore.dll

     

The calling thread must be STA, because many UI components require this

Could you help me correct my code?

Simplified code WPF :

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();////// el ERROR ocurre en esta linea ///
    System.Threading.Thread.Sleep(8000);
        MessageBox.Show("working 8 seg");

}
    
asked by emmtlm 14.01.2017 в 19:05
source

2 answers

2

What the error is trying to tell you is that it is illegal to create or manipulate visual controls (such as Grid ) on a thread other than the interface thread.

In this case, the problem is that Task.Run() executes the BrowserAsync method in a different thread, so you can not and should not create a Grid there. In fact, you should not run a MessageBox.Show() there either. Basically, you can not do anything in that method that wraps interface actions.

It's hard to come up with an appropriate solution other than to tell you that you can not do this, because it's obvious that your code is just a test and does nothing for now.

But if the intention is to execute a long job in the BrowserAsync method in a different thread so that the interface does not get stuck, that's fine. But you will have to limit yourself to doing and accumulating the result of this work using some structure that is not an interface control and then returning this result to the main interface thread, where there, you can use this result to make modifications to the interface controls .

For example, adjusting your situation a bit, let's say that when you click on the button what you want to do is a long calculation whose result you want to assign to a textbox.

Similar to your code, we might try to do the following:

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

private void CalculoLargo() {
    Thread.Sleep(30000); // simulando un cálculo largo
    int resultado = 100;
    textbox1.Text = $"Resultado del cálculo: {resultado}"; // error!!
}

But the statement that tries to assign the result to the textbox is not legal for the reasons already mentioned.

Rather, the correct way to perform the calculation on a different thread and then assign the result to the textbox is like this:

botontest.Click += 
    async (src, args) =>
    {
        int resultado = await Task.Run(() => CalculoLargo());
        textbox1.Text = $"Resultado del cálculo: {resultado}";
    };

private int CalculoLargo() {
    Thread.Sleep(30000); // simulando un cálculo largo
    return 100;
}

As you can see, the costly part is still done in a different thread so as not to break the interface thread. But when you have to assign the result to a visual control (textbox), you have to do it in the interface thread. In this example, this is achieved by doing that part after of await Task.Run() , when the code there is executed in the interface thread.

I hope this example gives you a model of how you can achieve your goal without receiving the error.

    
answered by 14.01.2017 в 19:43
1

You can not create a visual object in another thread. What you can do is call the thread of the view inside the other thread to create it using the Dispatcher of a visual element of the form or view.

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, ()=>{
 // crear elemento aqui
   Grid g = new Grid();
});

There are 2 methods you can use to do this.

  • Invoke : The thread waits for the thread of the view to end     create the visual element and continue its execution.

  • BeginInvoke :     The thread does not wait for the thread of the view to finish. In others     words, creates the visual element asynchronously to the running thread.

  • answered by 20.04.2017 в 04:46