7

my project a three tier architecture project talking to a WCF service in the backend. When the backend is able to fetch data from the service, it notifies the business layer using publish-subscribe, which in return notifies the GUI layer.

I have added an OpenFileDialog to my UI design using Visual Studios designer. A button event handler calls the ShowDialog message. However, once I click the button, the whole UI hangs.

Having googled around a bit, I found out that using delegates is the preferred way to handle tasks like this. However, with nor without delegate the problem persists.

Currently my code looks like this:

private void bOpen_Click(object sender, EventArgs e)
{
    Func<Image> del = delegate
    {
        OpenFileDialog d = new OpenFileDialog();
        if (d.ShowDialog() == DialogResult.OK)
        {
            return Image.FromFile(d.FileName);
        }

        return null;
    };

    Invoke(del);
}

I'm coming from the Java world, so I'm not really familiar with the intricacies of C# UI programming.

Anything I'm missing here?

Kage
  • 395
  • 1
  • 3
  • 9
  • 1
    I'm curious, why not just `private void bOpen_Click(object sender, EventArgs e) { OpenFileDialog d = new OpenFileDialog(); if (d.ShowDialog() == DialogResult.OK) { Image.FromFile(d.FileName); } };` – Vlad Jul 16 '11 at 14:59
  • It hangs without using the delegate too. I created the delegate because I found several websites saying that it's the preferred way to perform lengthy operation triggered by the GUI. Something like a SwingWoker in Java, I thought. – Kage Jul 16 '11 at 15:00
  • 2
    The preferred way that the sites mentioned must be to start the delegate in a separate thread. Something like `new Thread(del).Start();` – Vlad Jul 16 '11 at 15:01
  • But it's strange that the UI hangs, because `OpenFileDialog` must run an internal message loop itself. – Vlad Jul 16 '11 at 15:04
  • Have you tried this in a new Project? may your av or firewall blocks the program. – Orhan Cinar Jul 16 '11 at 15:06
  • @Kage: Your code should wrok without any problem. try @Orhan suggestion. – Jalal Said Jul 16 '11 at 15:09
  • Your GUI hangs ? What do you exactly mean? If you call ShowDialog() what you expect should happen? – Tigran Jul 16 '11 at 15:11
  • Communiation with the WCF service works as intended. They're both on localhost and not firewalled. – Kage Jul 16 '11 at 15:11
  • @Tigran: I expect an open file dialog to be shown. Instead Windows marks my application as "not responding". – Kage Jul 16 '11 at 15:12
  • 1
    Have you applied the STA thread attribute correctly to the main of the GUI process? http://msdn.microsoft.com/en-us/library/system.stathreadattribute.aspx – Martyn Lovell Jul 16 '11 at 17:03

6 Answers6

13
openFileDialog1->ShowHelp = true;

I put this line in my code then the problem was solved.

saiki miya
  • 131
  • 1
  • 4
  • 1
    Haha, this was the only solution for me in my situation! – Alexander Mar 24 '17 at 10:05
  • Worked also for me. Thats weird, and I'm courious why this makes the dialog working. – Sebastiano Apr 25 '17 at 09:50
  • This workaround was helpful in the early days of windows vista. Same code working properly on Windows XP, always hanged on Windows Vista. This was a simple workaround. – BiLaL Jun 15 '19 at 13:48
  • Searched all over the internet including many questions on SO and this is the only solution that removed the unexplained 5 second lag from OpenFileDialog.ShowDialog(). Who would have thought ShowHelp had anything to do with it? Yet somehow it does. – Joe Gayetty Feb 13 '20 at 16:35
  • It works on my old Windows 7 machine. d.ShowHelp = true; – Golden Thumb Nov 02 '22 at 20:10
9

I seem to have solved the problem adding the [STAThread] Attribute to the main method. I was told to do so once I ran the program in a debugger - which I hadn't done before because I ran the service from Visual Studio and the client regularly from Windows.

[STAThread]
public static void Main(string[] args)
{
    GUI gui = new GUI();
    gui.ShowDialog();
}

Can anybody explain what exactly is going on though

Kage
  • 395
  • 1
  • 3
  • 9
  • 1
    File open/save dialogs can only be shown in a single-threaded apartment model. That's quite well-explained by the documentation. I would have posted this originally had I seen the question. – Cody Gray - on strike Jul 17 '11 at 11:30
8

This tends to be an environmental problem, when you use OpenFileDialog a lot of shell extensions get loaded into your process. A misbehaving one can easily screw up your program. There are a lot of bad ones out there.

Debugging this is difficult, you need an unmanaged debugger since these shell extensions are unmanaged code. You might be able to tell something from the call stack when you break in after the deadlock. Windows debugging symbols required, enable the Microsoft symbol server. But the most effective approach is to use SysInternals' AutoRuns utility. Start by disabling all of the shell extensions that were not produced by Microsoft. Then start re-enabling the ones you cannot live without one by one.

And, as you found out, these shell extension expect to run on an STA thread and fail miserably when they don't get it. The UI thread of a program must always be STA, also to support the clipboard and drag-and-drop and various kinds of controls like WebBrowser. Normally always taken care of automatically by the [STAThread] attribute on the Main() method, put there by the project template. And the Application.Run() call, required to implement the STA contract. Deadlock when you don't.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 1
    The strange thing is that I can open a color chooser without problems. But that seems to confirm the shell extension thesis. – Kage Jul 16 '11 at 15:35
4

I believe the "delegate" prefered way actually refers to using a separate thread. I'm gonna give you an example using BackgroundWorker.

It would look like this:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            m_Worker.DoWork += new DoWorkEventHandler(m_Worker_DoWork);
            m_Worker.ProgressChanged += new ProgressChangedEventHandler(m_Worker_ProgressChanged);
            m_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_Worker_RunWorkerCompleted);
        }

        void m_Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Usually, used to update a progress bar
        }

        void m_Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Usually, used to add some code to notify the user that the job is done.
        }

        void m_Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //e.Argument.ToString() contains the path to the file
            //Do what you want with the file returned.
        }        

        private void bOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog d = new OpenFileDialog();
            if (d.ShowDialog() == DialogResult.OK)
            {
                m_Worker.RunWorkerAsync(d.FileName);    
            }            
        }

        BackgroundWorker m_Worker = new BackgroundWorker();
    }

Now, as for the reason your UI "hangs", it's because by default, your operation runs on the UI thread, so if you run something heavy the UI won't respond.

Louis Kottmann
  • 16,268
  • 4
  • 64
  • 88
  • If I can't use it on the Thread, I'm out of luck. The program hangs as soon as execution enters the ShowDialog() method. I can try to run it on a different machine. If it's as you said in the reply below, Hans, it should work on the other machine, right? – Kage Jul 16 '11 at 15:33
0

I also met this problem. And I tried all the solution here and none can solve it. Then I change the target framework from .Net Framework 4.7 to 4.6.2, the problem solved...

zxch3n
  • 387
  • 3
  • 9
0

I think my problem is different, as none of the above solutions worked for me.

I wrote temporary code to set the OpenFileDialog.FileName property to something not null or empty string (it was empty string when the hang up occured), and I restarted my computer. When I started up Visual Studio again, and ran it, it worked again without hanging up.

shieldgenerator7
  • 1,507
  • 17
  • 22
  • I had the problem that the OpenFileDialog hung when I tried to select a new folder with Filename set to "". Changing to FileName = "Image.jpeg" seems to fix it. – SimonKravis Mar 21 '23 at 00:55