C# WinForms: How to set Main function STAThreadAttribute

I get the following exception when calling saveFileDialog.ShowDialog() in a background thread:

Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.

According to this:

To fix the problem, insert the statement:

Threading.Thread.CurrentThread.ApartmentState = Threading.ApartmentState.STA;

in Main right before the Application.Run statement.

But the Application.Run statement is in Program.cs which seems to be generated code so any changes might be unexpectedly lost. Also, I could not find a way to set current thread to STA in the project or main form properties but maybe I am looking in the wrong place. What is the proper way to call saveFileDialog.ShowDialog() in a background thread?


Solution 1:

Solution very easy; Just add this on top of the Main method [STAThread]

So your main method should look like this

 [STAThread]
 static void Main(string[] args)
 {
     ....
 }

It works for me.

Solution 2:

ShowDialog() shouldn't be called from a background thread - use Invoke(..).

Invoke((Action)(() => { saveFileDialog.ShowDialog() }));

Solution 3:

this should work if you are creating the thread in which you call the showDialog:

var thread = new Thread(new ParameterizedThreadStart(param => { saveFileDialog.ShowDialog(); }));
 thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Solution 4:

Add following code on FormLoad

private void Form1_Load(object sender, EventArgs e)
{
    Thread myth;
    myth = new Thread(new System.Threading.ThreadStart(CallSaveDialog)); 
    myth.ApartmentState = ApartmentState.STA;
    myth.Start();
}

Here CallSaveDialog is a thread and here you can call ShowDialog like this

void CallSaveDialog(){saveFileDialog.ShowDialog();}

Solution 5:

On your MainForm:

if (this.InvokeRequired) { 
 this.Invoke(saveFileDialog.ShowDialog()); 
} else { 
 saveFileDialog.ShowDialog(); 
}

Or, if you will have other methods that need to be run from the UI thread:

  private void DoOnUIThread(MethodInvoker d) {
     if (this.InvokeRequired) { this.Invoke(d); } else { d(); }
  }

Then, call your method as such:

 DoOnUIThread(delegate() {
    saveFileDialog.ShowDialog();
 });