5

I am trying to finish my static Prompt class to be able to call it from anywhere. But the problem is couldn't make the dialog show. I am already using [STAThread] and here is my code.

public static string ShowFileDialog()
{
    string selectedPath = "";
    var t = new Thread((ThreadStart)(() =>
    {
        FolderBrowserDialog fbd = new FolderBrowserDialog();
        fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
        fbd.ShowNewFolderButton = true;
        if (fbd.ShowDialog() == DialogResult.OK)
        {
            selectedPath = fbd.SelectedPath;
        }
    }));
    t.SetApartmentState(ApartmentState.STA);
    t.Start();

    t.Join();
    return selectedPath;
}

public static class Prompt is my Prompt Class. I am calling it from public partial class Dashboard : Form class

Thank you for your helps.

Ahmet Can Güven
  • 5,392
  • 4
  • 38
  • 59
  • Could you please describe your use case of using the ShowFileDialog() when the dialog is not visible? Could it be that it is visible but not in focus? – Yaugen Vlasau Sep 07 '15 at 09:20
  • I just want to ask user a path to file when the system received a command from socket. – Ahmet Can Güven Sep 07 '15 at 09:21
  • Where are you calling ShowFileDialog() from? – Akansha Sep 07 '15 at 09:21
  • public static class Prompt is my Prompt Class. I am calling it from public partial class Dashboard : Form class – Ahmet Can Güven Sep 07 '15 at 09:29
  • @HansPassant Please write this as an answer. I just learned that Forms requires owner windows from you and I solved my problem. – Ahmet Can Güven Sep 07 '15 at 09:31
  • @AhmetCanGüven not always a window require another window. there various cases to show windows, there is API that can make a window focused or bring it on TopMost level and so one. In case of windows service you won't be able to dispay any window at all. So when it goes in windows and modal dialogs there should be clear from where you start a window. – Yaugen Vlasau Sep 07 '15 at 09:50

1 Answers1

8

It surely works just fine when you don't get an exception. But yes, pretty decent odds that you don't see the dialog. Pretty ugly problem, you don't have a taskbar button either. Only way to find it back is by minimizing the other windows on the desktop.

A dialog, any dialog, must have an owner window. You are supposed to pass that owner to the ShowDialog(owner) method overload. If you don't specify one that it goes looking for an owner by itself. Underlying call is GetActiveWindow(). To come up with nothing, the desktop window now becomes the owner. That isn't good enough to ensure that the dialog window is in front.

At a minimum you must create that owner window, you'll now at least have the taskbar button. Like this:

    using (var owner = new Form() { Width = 0, Height = 0,
        StartPosition = FormStartPosition.CenterScreen,
        Text = "Browse for Folder"}) {
        owner.Show();
        owner.BringToFront();
        FolderBrowserDialog fbd = new FolderBrowserDialog();
        fbd.RootFolder = System.Environment.SpecialFolder.MyComputer;
        fbd.ShowNewFolderButton = true;
        if (fbd.ShowDialog(owner) == DialogResult.OK) {
            selectedPath = fbd.SelectedPath;
        }
    }

Still doesn't guarantee that the dialog is visible, you cannot push a window into the user's face when he's interacting with another window. But at least there's a taskbar button.

I'll very hesitantly show the hack around that, don't use it:

    owner.Show();
    var pid = System.Diagnostics.Process.GetCurrentProcess().Id;
    Microsoft.VisualBasic.Interaction.AppActivate(pid);

The proper way to draw the user's attention and get him to interact with your UI is NotifyIcon.ShowBalloonTip().

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536