BackgroundWorker thread must be STA

2020-04-11 01:42发布

I have a BackgroundWorker to call a function to do a long process at BackgroundWorker _DoWork, when error occur in the function I will prompt a customized messagebox:

 WPFMessageBoxResult result = WPFMessageBox.Show("Activation Fail", "Error!!", WPFMessageBoxButtons.OK, WPFMessageBoxImage.Error);

The exception below happens at WPFMessageBoxResult class :

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

Thank you.

标签: c# wpf
4条回答
ゆ 、 Hurt°
2楼-- · 2020-04-11 02:07

Your background thread is just a worker thread and not a user interface thread. WPF and WinForms both require that the thread performing user interface actions be marked as STA (Single Threaded Apartment) because the user interface code is not thread safe. They also require that you add a message pump so that windows messages are dispatched.

I recommend that instead of showing the message box in your worker thread you send a message to your main user interface thread and have that thread show the message box. To do this you should pass a reference to the Dispatcher from the main UI thread into the worker thread. Then use the Dispatcher.BeginInvoke to request a delegate be called back on the main thread.

Alternatively you can wait for the background thread to complete and then check the result and show the appropriate answer to the user. Either way the worker thread should not be directly interacting with the user interface.

查看更多
家丑人穷心不美
3楼-- · 2020-04-11 02:13

You should not try to interact with any UI components from a background thread.

One way could be to catch the exception in your doWork method and assign it to the backgroundworker's result property and then check if that result is a type of exception or not null if you are not using the result for anything else. then check for it in the backgroundWorker_completed event.

BackgroundWorker_DoWork(sender, )
{
    try
    {
       // do work        
    }
    catch (Exception ex)
    {
         BackgroundWorker w = sender as BackgroundWorker;
         if (w != null)
             w.Result = ex;
    }
}

then

BackgroundWorker_Completed()
{
    if (s.Result != null && e.Result is Exception)
    {
       Exception ex = e.Result as Exception;
       // do something with ex
    }
}
查看更多
你好瞎i
4楼-- · 2020-04-11 02:27

Usually with Winforms/WPF you use Invoke() to jump onto the UI thread if you need to interact with the UI from a long-running task. You can call invoke from any object that belongs to the UI, but be sure when in the invoke scope to only do as little code as possible. Since this code is on the UI thread it will block/hang the UI if it takes too long.

public void BackgroundWorkerMethod()
{
    try
    {
        // do work
    }
    catch (Exception e)
    {
        uiObject.Invoke(new Action(() => {
            // now you are on the UI thread
            Message.ShowMessage(e.Message);
        });
    }
}
查看更多
一夜七次
5楼-- · 2020-04-11 02:29

You must use this method

 void BGW_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            Dispatcher.BeginInvoke(new Action(() =>
            {
                 Button btn = new Button();
                 btn.Width = 100;
                 btn.Height = 50;
                 btn.Content = "Test";
                 myG.Children.Add(btn);
            }
            ));
        }
            catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }
查看更多
登录 后发表回答