30

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?

jacknad
  • 12,983
  • 39
  • 119
  • 191
  • http://stackoverflow.com/questions/428494/is-it-possible-to-use-showdialog-without-blocking-all-forms – ba__friend Jun 16 '11 at 14:36
  • 3
    [Don't do UI in a background thread.](http://blogs.msdn.com/b/oldnewthing/archive/2007/10/18/5501378.aspx) – Craig Stuntz Jun 16 '11 at 14:37
  • 1
    Program.cs is created by the wizard, but never regenerated (unlike *.Designer.cs, etc, where your changes really would be lost). – Ben Voigt Mar 04 '15 at 15:05

5 Answers5

56

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.

Kirill Kobelev
  • 9,986
  • 6
  • 27
  • 48
MILAD
  • 629
  • 1
  • 5
  • 7
31

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

Invoke((Action)(() => { saveFileDialog.ShowDialog() }));
Nathan
  • 5,874
  • 2
  • 31
  • 60
13

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();
Mg.
  • 1,419
  • 2
  • 15
  • 27
7

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();}
Breeze
  • 1,912
  • 2
  • 33
  • 40
santosh Kundkar
  • 149
  • 1
  • 3
1

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();
 });
C-Pound Guru
  • 15,359
  • 6
  • 47
  • 67