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
  • 13,483
  • 40
  • 124
  • 194
  • 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

58

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
  • 10,252
  • 6
  • 30
  • 51
MILAD
  • 649
  • 1
  • 5
  • 7
31

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

Invoke((Action)(() => { saveFileDialog.ShowDialog() }));
Nathan
  • 6,095
  • 2
  • 35
  • 61
14

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,469
  • 2
  • 16
  • 29
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
  • 2,010
  • 2
  • 32
  • 43
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,967
  • 6
  • 46
  • 67