Reputation: 800
I have forms: Splashscreen
, Search
, and NewEntry
Program.cs
starts Splashscreen
which checks some parameters and upon success (check user name, permissions, etc) opens Search
form. From there I can call the NewEntry
form.
So since the Splashscreen
is the primary form called by the Main()
function, once it closes, the app closes (this is the expected behaviour).
So what I did is from within Splashscreen
I start the Search
form as a dialog and hide Splashscreen
, so it waits for the Search
to close. As soon as it closes, I also close the Splashscreen
and it all seemed to make sense at the time. From the Search
form I open the NewEntry
form (from a button click) also as a dialog (I don't want users clicking back and forth and creating multiple NewEntry
windows).
Today I had to add a feature that allows the user to select a file. As an obvious choice, I used an OpenFileDialog
. But as soon as I call .ShowDialog()
method, the whole app just freezes.
I've read Windows Forms GUI hangs when calling OpenFileDialog.ShowDialog() and OpenFileDialog.ShowDialog() freezing application c# and a bunch of other posts here and on other sites, and when I almost lost hope, I came across this http://wishmesh.com/2011/06/call-to-openfiledialog-or-savefiledialog-hangs-or-freezes/
I do have the [STAThread]
attribute set on my Main()
function
And one particular point of interest is: For OpenFileDialog the ShowHelp property must be explicitly set.
And also ... They don’t have to be set to true, they just have to be initialized to either true or false.
So when I set the ShowHelp
to true
, the dialog shows up (with the useless Help button).
A further research showed that when I execute (new OpenFileDialog()).ShowDialog();
within Program.cs
or within Splashscreen
, it works just fine; however, when called from a dialog, there is a hang (without the ShowHelp
). Furthermore, a MessageBox
shows up just fine from the Dialog
...
So is there a way to make this work? Or should I manage my windows differently?
For example, have Search
as the main startup window, then before the window shows, call Splashscreen
as a dialog, and if it fails, just close the main window? But then, how would I handle the NewEntry
to be able to show OpenFileDialog
or FolderBrowserDialog
?
Thanks.
Upvotes: 2
Views: 3245
Reputation: 800
I really appreciate your help in this matter.
So to summarise, I created Form1
and Form2
to test some code and here is what I have (only relevant portions):
// Form1:
void Button1Click(object sender, EventArgs e)
{
Form2 f2=new Form2();
this.Hide();
f2.Show(this);
}
// Form2:
void Form2Load(object sender, EventArgs e)
{
if (this.Owner==null) throw new ArgumentException("This window must be called with the Owner property set!");
// or just ignore, or show a MessageBox and close, or use your imagination...
}
void Form2FormClosed(object sender, FormClosedEventArgs e)
{
// sanity check...
if (this.Owner!=null && !this.Owner.Visible) this.Owner.Show();
}
So when I call Form2
, I first hide the current form and use an overload of Show()
that takes 1 argument and sets the Form2
's Owner
property. Alternately I could just call f2.Owner=this;
and then f2.Show();
Then when/after Form2
is closed, I check if Owner was set and show that form.
Now back to the original question, here is what I have inside Program.cs
:
if ((new Splashscreen()).ShowDialog() == DialogResult.OK)
Application.Run(new Search());
So now Search
only shows if Splashscreen
returned with DialogResult.OK
and when Search
is closed, the application exits properly.
Thanks for all the help.
This saved me tons of time.
P.S.
I wish I could mark both answers as answers, going to toss a coin and randomly mark one.
Upvotes: 1
Reputation: 2758
If in your program.cs
, you are calling this: Application.Run(new splashscreen());
, if it were me, I would do this instead so that you can have multiple forms open after the splashscreen closes.
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new splashscreen().ShowDialog();
Application.Run(new Search());
}
}
This will show the splashscreen, and then once everything's loaded, you can open the search form and close the splashscreen, and won't have to call ShowDialog()
. (you'll have to call application.End()
to end the application.)
Upvotes: 2
Reputation: 914
The part that concerns me the most is when you say you have SplashScreen wait for Search to close. If you are doing this
if (search.ShowDialog() == DialogResult.OK)
{
Show();
}
Then you have frozen the UI thread for the SplashScreen. Since it's the main form things are not likely to work as expected. I suggest changing the code to this.
Hide(); // Hides SplashScreen
Search search = new Search();
search.ParentForm = this;
search.Show(); // Show Search without freezing SplashScreen thread
ParentForm is a public variable I added to Search. This should be private and access should be through a getter/setter but this keeps the code example short.
public partial class Search: Form
{
public SplashScreen ParentForm;
...
}
Next you will need to add a handler to handle the Search form closing. This will show SplashScreen.
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
ParentForm.Show();
}
After making these changes OpenFileDialog show work fine.
Upvotes: 3