Sunday, November 9, 2008

OpenFileDialog.showDialog hangs on Vista

OpenFileDialog began hanging when called directly from some of my code. (I'm dealing with C# 2.0 here.)

Turns out it doesn't run in it's own thread, but takes over your main thread. Vista just isn't a big fan of this. To get around it you need to invoke OpenFileDialog from within another thread. I stumbled upon this code that will work nice any time you need to popup another dialog window (such as a process indicator or built in ones like OpenFileDialog). Hopefully our pals over in Redmond fix up OpenFileDialog to just do this by default in the future.

I stumbled upon this code out in the blogosphere (https://forums.microsoft.com) awhile ago.

public class Invoker
{
public OpenFileDialog InvokeDialog;
private Thread InvokeThread;
private DialogResult InvokeResult;

public Invoker()
{
InvokeDialog = new OpenFileDialog();
InvokeThread = new Thread(new ThreadStart(InvokeMethod));
InvokeThread.SetApartmentState(ApartmentState.STA);
InvokeResult = DialogResult.None;
}

public DialogResult Invoke()
{
InvokeThread.Start();
InvokeThread.Join();
return InvokeResult;
}

private void InvokeMethod()
{
InvokeResult = InvokeDialog.ShowDialog();
}
}

Usage :

Invoker I = new Invoker();

if (I.Invoke() == DialogResult.OK)
{
MessageBox.Show(I.InvokeDialog.FileName, "Test Successful.");
}
else
{
MessageBox.Show("Test Failed.");
}

5 comments:

Unknown said...

Thank you, thank you, thank you! I ran into this and kept thinking the problem was that the UI thread was what needed to be doing the showDialog(). Many of hours wasted racking my brain, and this works perfectly. Thanks again.

Unknown said...

Thanks a lot for this example! Works great! You saved my time and energy! Thanks again!

Brouk said...

Thanks a lot, you saved my poor programmers life ;o)

John said...

Thanks. Truly we are not worthy

Unknown said...

Or, simpler:

private static DialogResult InvokeFileDialog( FileDialog dialog )
{
DialogResult result = DialogResult.None;
Thread t = new Thread(
new ThreadStart(
delegate
{
result = dialog.ShowDialog();
} ) );
t.SetApartmentState( ApartmentState.STA );
t.Start();
t.Join();
return result;
}