I'd like to have a welcoming form, named the StartForm. This closes, then opens my MenuForm.
Current problem is: First one stays open, doesn't close to show the second one.
I tried several things, like simply showing and hiding them. I now try Application.run and then hide it. Unfortunately it stays open. And doesnt Application.run the second form.
static void Main()
{
Form StartForm = new Main();
MForm MenuForm = new MForm();
Application.Run(StartForm);
//
Task.Delay(500).ContinueWith((t) =>
{
StartForm.Hide();
Application.Run(MenuForm);
});
}
I expected this to Close the first form after waiting the delay, but it stays open.
Calling Application.Run() causes a new application message loop to begin running on the current thread. If a subsequent call to Application.Run() is made while the first application is running an InvalidOperationException is thrown according to the docs. However, this is not actually possible in your case as your call to Application.Run() is being invoked on the UI thread, which blocks the execution of any following code until it exits.
Instead, what we need is to bootstrap the application by using Application.Run(new Main()) and then inside of the Main form we will handle the displaying and hiding behaviour.
Here is how I would suggest achieving this:
Firstly, in your Main method, replace everything with Application.Run(new Main());.
Then inside of your Main form create a method like the following:
private void Main_Shown(Object sender, EventArgs e)
{
Task.WaitAll(Task.Delay(500));
this.Hide();
var menuForm = new MForm();
menuForm.Closed += (obj, args) => { this.Show(); };
menuForm.Show();
}
And lastly, go into your Main.Designer.cs file and make sure you subscribe the Shown event to Main_Shown method you just created in the InitializeComponent method like so:
this.Shown += new System.EventHandler(this.Main_Shown);
Explanation of what is going on here:
According to the docs the Form.Shown Event gets fired the first time a form is shown to the user. This is perfect for this use case, so we 'hook' into it and respond to it by awaiting a delay of 500 milliseconds.
Afterwards we hide the current (Main) form, create the new (MForm) form and show it. But the more important detail is that we subscribe to that form's Closed event so that when it is closed by the user, the Main form shows itself again.
use timer to Open Second form in Firstform
and Hide Firstform after show Secondform.
like this.
Main
static void Main()
{
Form StartForm = new Main();
Application.Run(StartForm);
}
FirstForm
set timer with interval 5000 and Enable it.
private void timer1_Tick(object sender, EventArgs e)
{
MForm MenuForm = new MForm();
this.Hide();
MenuForm.Show();
timer1.Stop();
}
Related
I tried opening a second form using a button on my main form, but when I close the second window, I can't open it again.
I added the following code to my main form:
settings_window secondForm = new settings_window();
private void settings_button_Click(object sender, EventArgs e)
{
secondForm.Show();
}
But when I try to open the second form named settings_window the second time, I get the following error: System.ObjectDisposedException.
I found the following code to fix this but I don't know where to place it:
private void settings_window_FormClosing(object sender, FormClosingEventArgs e)
{
this.Hide();
e.Cancel = true; // Do not close the form.
}
You can avoid storing references of Forms and use a simple generic method that shows a Form when an instance of it already exists or creates a new one (and shows it) when none has been created before:
private void ShowForm<T>() where T : Form, new()
{
T? f = Application.OpenForms.OfType<T>().SingleOrDefault();
if (f is null) {
f = new T();
f.FormClosing += F_FormClosing;
}
f.Show();
BeginInvoke(new Action(()=> f.WindowState = FormWindowState.Normal));
void F_FormClosing(object? sender, FormClosingEventArgs e)
{
e.Cancel = true;
(sender as Form)?.Hide();
}
}
When you need it, call as ShowForm<SomeFormClass>(), e.g.,
ShowForm<settings_window>()
Note:
This code uses a local method to subscribe to the FormClosing event.
You can use a standard method, in case this syntax is not available.
BeginInvoke() is used to defer the FormWindowState.Normal assignment. This is used only in the case you minimize a Form, then right-click on its icon in the TaskBar and select Close Windows from the Menu. Without deferring this assignment, the minimized Form wouldn't show up again.
When the starting Form closes, all other Forms close as well
This code supposes nullable is enabled (e.g., see object? sender). If nullable is disabled or you're targeting .NET Framework, remove it (e.g., change in object sender)
Is secondForm a private field of the main form class?
It should work then.
Alternative solution is to show it as as modal - ShowDialog()
Also if you want to save some data in your second form, just use some data initialization from constructor, then saving to first/parent form.
I think you need to create a new instance of the form each time you want to open it. It will create a new instance of the settings_window form each time the button is clicked.
private void settings_button_Click(object sender, EventArgs e)
{
// Create a new instance of the form
settings_window secondForm = new settings_window();
secondForm.Show();
}
Your code shows a class that you have named settings_window, which gives us a hint about what its intended use might be. In general, for a form that behaves "like" a settings window, that you can call multiple times using the same instance, you can declare a member variable using this pattern:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Provide some means, like a menu or button, to show 'secondForm'
settingsMenu.Click += onClickSettingsMenu;
// Dispose the settings_form when the MainForm does.
Disposed += (sender, e) => secondForm.Dispose();
}
// By instantiating it here, its public default or persisted
// properties are immediately available, for example even
// while the main form constructs and loads the initial view.
settings_window secondForm = new settings_window();
private void onClickSettingsMenu(object? sender, EventArgs e)
{
if(DialogResult.OK.Equals(secondForm.ShowDialog()))
{
// Apply actions using the properties of secondForm
}
}
}
This is suitable for any form when you want to:
Repeatedly show and hide the form (e.g. a "Settings" form where the user can change the options multiple times).
Retrieve the default or the persisted properties of the form from the outset even if it's never been shown.
Use any of the form's public properties (e.g. GameLevel, SortType etc.) at any given moment while the app is running, even if the form isn't currently visible.
Display the form modally meaning that "no input (keyboard or mouse click) can occur except to objects on the modal form".
The reason it works is that calling ShowDialog (unlike calling Show) intentionally does not dispose the window handle, and this is to support of this very kind of scenario. The app is then responsible for disposing the resource when the app closes.
The Microsoft documentation for ShowDialog explains how this works.
Unlike non-modal forms, the Close method is not called by the .NET Framework when the user clicks the close form button of a dialog box or sets the value of the DialogResult property. Instead the form is hidden and can be shown again without creating a new instance of the dialog box. Because a form displayed as a dialog box is hidden instead of closed, you must call the Dispose method of the form when the form is no longer needed by your application.
I am trying to create a windows form that gets displayed for 2 seconds when triggerd by an event, and then closes automatically.
I have tried several options. This is my current code:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
Thread.Sleep(2000);
this.aletPopup.Close();
This preforms the actions that I desire, however, when the form loads it does not load the label or image which is on the form. Instead, the area where the image and label are become transparent. My desired output is this:
I have also tried using this.aletPopup.ShowDialog();, which does display the graphics. However, the form will not close automatically when using this method.
EDIT: I am attempting to use
Michael Perrenoud's solution. However, I cannot get the form to close. I have a timer set at a 2000ms interval which is initally disabled. Am I overriding the OnShown correctly?
public AlertPopForm()
{
InitializeComponent();
}
private void closingTimer_Tick(object sender, EventArgs e)
{
closingTimer.Enabled = false;
this.Close();
}
private void AlertPopForm_OnShown(object sender, System.EventArgs e)
{
closingTimer.Enabled = true;
closingTimer.Start();
}
Instead, how about leveraging ShowDialog, and then using a Timer on the dialog form. In the Tick event of the Timer, close the form.
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.ShowDialog();
You could even pass the interval into the .ctor of the dialog form if you wanted some flexibility.
It's very important to note here that you'd need to leverage the OnShown override to actually Start the Timer so the form is in fact shown to the user.
The reason can be in Message Loop. When you block your thread by Thread.Sleep, it also blocks Message loop.
You can make like this:
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
for(var i = 0; i<= 200; i++)
{
Thread.Sleep(10);
Application.DoEvents();
}
this.aletPopup.Close();
DoEvents will process messages from message queue during that time.
When calling Thread.Sleep you're blocking the UI thread, thus preventing it from processing UI events.
You need to ensure that Close is called after 2 seconds without actually blocking the main thread. There are a number of ways of doing this, such as using a Timer, or something like Task.Delay:
aletPopup.StartPosition = FormStartPosition.CenterScreen;
aletPopup.Show();
Task.Delay(TimeSpan.FromSeconds(2))
.ContinueWith(t => aletPopup.Close(),
TaskScheduler.FromCurrentSynchronizationContext());
The reason this is happening, is that you are halting the thread that draws the form. So the form has time to display, but as it's being drawn, the thread is being stopped.
Easy enough to fix....
Add an event handler to the popup for the Load event with the following handler:
private async void handleLoad(Object sender, EventArgs args)
{
await Task.Delay(2000);
Close();
}
Remark
Because you used Show(), the user could always click around this popup. If this is undesirable, then use ShowDialog() instead.
Did you try a refresh to redraw the form?
this.aletPopup.StartPosition = FormStartPosition.CenterScreen;
this.aletPopup.Show();
this.alertPopup.Refresh();
Thread.Sleep(2000);
this.aletPopup.Close();
I have a windows forms question:
Program.cs:
Application.Run(new frmStart());
frmStart: on btnLoad_Click,
frmLoad formLoad = new frmLoad();
formLoad.Show();
this.Hide(); // if I do a this.Close(); after it shuts down and doesn't get to show the form
frmLoad: on btnCancel_Click:
Application.Exit();
// or this.Close();
// or even: base.Close();
The form disappears but the program doesn't end, I still have to press the blue "Stop Debugging" to make it stop.
I have been looking... I know it is possible to make the program really stop, and not just freeze when you close the second form, even if you don't keep the first form on the screen, but can't remember and can't figure out how.
Ack, -1 on Application.ExitThread!
The issue is that you haven't closed the main form. The simplest way is to hook onto the 2nd form's Closed event and have it close the main form. For example the code to open the 2nd form changes to:
var newForm = new frmLoad();
newForm.FormClosed += (closedSender, closedE) => Close();
newForm.Show();
Hide();
This essentially sets up so that when the frmLoad form closes, the main form calls it's Close() method. I used a Lambda expression for the event handler, but you can just as easily create a private method accepting an (object sender, EventArgs e) and point .FormClosed at it.
*Edit: Sorry, missed that you only want to close on certain state. In which case on your frmLoad, create a public property such as:
public bool UserCancelled
{
get;
private set;
}
where the Cancel button sets this to True before closing the form. Your event handler in the main form changes to:
var newForm = new frmLoad();
newForm.FormClosed += (closedSender, closedE) =>
{
if (newForm.UserCancelled)
Close();
};
newForm.Show();
Hide();
In frmStart add:
public static frmStart Current;
Then in the constructor add:
Current = this;
Then in frmLoad: on btnCancel_Click:
frmStart.Current.Close();
You really should call Close() on both. That's the only clean way as otherwise the first form never is told to close down and doesn't clean up.
You may know that it's safe to do this, but someone else working on the code later may add code in the OnClose in the first form that they need called. They will say not nice things about you when they finally figure out why their code is not called.
If you close both, then your app will exit.
Please use the Application.ExitThread() method, the method exits the message loop on the current thread and closes all windows on the thread.
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.exitthread
I vote yuck on all the answers. Override Form Closing in your primary form and close the secondary form first.
I am new to win forms (C#). The current form that I'm making has the option to create a new (blank) instance of itself, but if I ever close that first instance, all the others close as well. This is not what I want to happen. (Closing any form opened up from the first doesn't close any others, though)
I was thinking it may be because I am creating a new copy from within one of the copies/objects, so it is tied to that first object so it closes when it does; however, if I open up another form from the one opened from the first one and then close that one that was opened from the first one, the one that I opened up from it doesn't close.
I want it so that I can still close that first form without the others closing, and that when the last one closes, the program stops running.
Is there any way to do this?
You can run as many forms as you need but each in the separate thread
using System;
using System.Threading;
using System.Windows.Forms;
public partial class MyForm: Form
{
public MyForm()
{
InitializeComponent();
}
private void Button1Click(object sender, EventArgs e)
{
var t = new Thread(() => Application.Run(new MyForm()));
t.Start();
}
}
You should not have to close the Entry Point (MainForm) Form. Check the Main() method code in Program.cs code file.
public static void Main(string[] args)
{
// Starts the application.
Application.Run(new Form1());
}
Read this page.
To prevent a form from closing, handle the Closing event and set the
Cancel property of the CancelEventArgs passed to your event handler to
true.
You dont need to create new thread for every form. Just use this:
Form newForm1 = new Form();
this.Hide();
newForm1.ShowDialog();
this.Close();
Shortly:
The first form of every windows application is the main form.
If it closes, so does the application.
(See Program.cs for more details)
To solve this you can call Application.Run (While I don't know if it's smart or not)
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
new Form1().Show(); // any entry point with form
Application.Run(); // without main form
}
}
Program.cs
You can use like this code block.
But when any form closed, application not finished.
(Even if the last a form in application.)
Because application not included mainform.
If application has not any a opened form.
Application will suspend in process. You can see then the task manager.
As a result you will call manually Application.Exit() method in each form close events.
The first time I open one of my child forms from the main form it opens normally. If I close the first instance of the child form and then reopen it however I get a crash the first time I try to call CreateGraphics() outside of the OnPaint() method. The exception I get is: "Cannot access a disposed object. Object name: 'MyControlClass'."
I've set breakpoints to monitor what's going on. Dispose() is called as expected the first time I close the form. When I start the form the second time MyControlClass's constructor is called, and the Dispose method isn't called prior to the exception. At the point of the exception this is still valid. Because of that I'm wondering if somehow it's actually the static component of MyControlClass that ended up being disposed; not the instance object.
I am creating a new copy of the form each time the button to show it is called. MyChildForm is a member held by my mt parentform and is also used to prevent multiple copies of the form from being opened at once.
ShowMyForm()
{
myChildForm = new myChildForm Form();
myChildForm.FormClosed += myChildFormFormClosed;
myChildForm.Show();
}
private void myChildFormFormClosed(object sender, FormClosedEventArgs e)
{
myChildForm = null;
}
The line of code that crashes: MyControlClass inherits from MyControlClassBase, which in turn inherits from MyControlClassBaseBase. This line of code is triggered by a mouse event in MyControlClassBase and is in MyControlClassBaseBase. The code after this would take a cached image of MyControl, display it using the newly created Graphics object, and then draw an overlay based on the mouse cursor position.
Graphics g = CreateGraphics();
PS Since I'm sure someone will ask: The rube goldberg in question is due to the utter fail that is fake 'transparency' in winforms in any but the most trivial cases and the fact that MyControlClass takes too long to paint to keep up with the mouse cursor; but that's a separate question entirely.
After a form is closed, it is disposed - meaning that it exists just to read fields.
If you want to show the same form again, create another instance or just hide it instead of closing.
MyForm f = new MyForm();
f.Show();
// After closed, it will be disposed.
So we need to do the same steps to show it again:
f = new MyForm();
f.Show();
Now you will get a brand new and identical form.
But to hide it when closed, you might need this code:
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
Note that it will not work with modal forms. (ShowDialog();)
(Thanks to Sorax) This will also not work with MDI children.