The calling thread must be STA, because many UI co

2019-08-08 05:38发布

问题:

I am using the MessageBox provided by WPF Toolkit. And I get the error

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

new Thread(new ThreadStart(delegate
{
    MessageBox.Show("Opeartion could not be completed. Please try again.","Error",MessageBoxButton.OK,MessageBoxImage.Error);
})).Start();

How can I set the ApartmentState in this case

Edit: I am trying to display a modeless MessageBox using MessageBox control of WPF Toolkit. So far the code I have is as follows:

void SomeFunction()
{
// calls to some UI, and processing and then

var th = new Thread(new ThreadStart(delegate
                                        {
                                           MessageBox.Show("Opeartion could not be completed. Please try again.",
                                                "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                                        }));

                                        th.SetApartmentState(ApartmentState.STA);
                                        th.Start();
                                    }
}

回答1:

Like the frames of the user interface, like many Windows Forms, WPF also imposes a single threading model, which means you can only access a specified derivative DispatcherObject thread that creates it. In Windows Forms controls that implement the interface ISynchronizeInvoke, this interface exposes a set of methods such as Invoke and BeginInvoke to impose a contract common thread synchronization we can use to access a control from another thread. In WPF, we also have that kind of thing, but these operations are involved in a class called Dispatcher, Dispatcher WPF is the way to allow this kind of thread synchronization model.

The following is an example of how to modify the TextBox.Text property when the caller is in a different thread:

// Resets textbox text from another thread
textBox.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
    textBox.Text = "New text";
}));


回答2:

EDITED

According to MSDN There exists builtin modal MessageBox in WPF but if you want to use Modeless MessageBox then you have to create custom window and then show it. Creating, showing and and returning value from custom modeless MessageBox is not very tough. You can see this link

It is not wiser to use different thread for messagebox only. Anyway you can set single apartment state by following...

  Thread th = new Thread(new ThreadStart(delegate
  {
    MessageBox.Show("Opeartion could not be completed. Please try again.", "Error",MessageBoxButtons.OK,MessageBoxImage.Error);
  }));

  th.ApartmentState = ApartmentState.STA;
  th.Start();


回答3:

// enable unit test to mock a dispatcher
var dispatcher = Dispatcher.CurrentDispatcher;
if (Application.Current != null)
{
    // use the application dispatcher if running from the software
    dispatcher = Application.Current.Dispatcher;
}

if (dispatcher != null)
{
    // delegate the operation to UI thread.
    dispatcher.Invoke(
        delegate
        {
            MessageBox.Show("Opeartion could not be completed. Please try again.","Error",MessageBoxButton.OK,MessageBoxImage.Error);
        });
}