I am trying to open a new windows form, however it seem to close immediately every time.
it works if i use ShowDialog() instead of Show(), but that is not my intention.
class Forms
{
Main mainForm;
Thread mainThread;
public Forms()
{
}
private void ThreadProc()
{
try
{
mainForm = new Main();
mainForm.Show();
}
catch { }
}
public void startMain()
{
mainThread = new Thread(new ThreadStart(ThreadProc));
mainThread.SetApartmentState(ApartmentState.STA);
mainThread.Start();
}
}
The problem is your mainThread does not run any message loop (that is responsible to react to all the GUI-related messages like resizing, button clicks, etc...), and so after calling mainForm.Show() the thread finishes.
In fact winforms applications usually start like this:
Application.Run(new MainForm());
where, as you can see in the MSDN documentation, Application.Run starts a standard message loop in the current thread and shows the form.
If you use ShowDialog() it works because modal forms run their own message loop internally.
I don't know what you are trying to accomplish but ShowDialog might be the easiest solution; in case you don't like it just replace your mainForm.Show with Application.Run(mainForm) and it should work.
You would need to use Application.Run to start the application message loop, otherwise the program would act like a console app and close once its code has finished executing.
Add using System.Windows.Forms; to the top of the class.
Then change mainForm.Show(); to Application.Run(mainForm); inside ThreadProc.
You should use:
Application.Run(new MainForm());
Begins running a standard application message loop on the current
thread, and makes the specified form visible.
Related
I have a published application in C#. Whenever I close the main form by clicking on the red exit button, the form closes but not the whole application. I found this out when I tried shutting down the computer and was subsequently bombarded by lots of child windows with MessageBox alerts I added.
I tried Application.Exit but it still calls all the child windows and alerts. I don't know how to use Environment.Exit and which integer to put into it either.
Also, whenever my forms call the FormClosed or FormClosing event, I close the application with a this.Hide() function; does that affect how my application is behaving?
From MSDN:
Application.Exit
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed. This is the code to use if you are have called Application.Run (WinForms applications), this method stops all running message loops on all threads and closes all windows of the application.
Environment.Exit
Terminates this process and gives the underlying operating system the specified exit code. This is the code to call when you are using console application.
This article, Application.Exit vs. Environment.Exit, points towards a good tip:
You can determine if System.Windows.Forms.Application.Run has been called by checking the System.Windows.Forms.Application.MessageLoop property. If true, then Run has been called and you can assume that a WinForms application is executing as follows.
if (System.Windows.Forms.Application.MessageLoop)
{
// WinForms app
System.Windows.Forms.Application.Exit();
}
else
{
// Console app
System.Environment.Exit(1);
}
Reference: Why would Application.Exit fail to work?
I know this is not the problem you had, however another reason this could happen is you have a non background thread open in your application.
using System;
using System.Threading;
using System.Windows.Forms;
namespace Sandbox_Form
{
static class Program
{
private static Thread thread;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
thread = new Thread(BusyWorkThread);
thread.IsBackground = false;
thread.Start();
Application.Run(new Form());
}
public static void BusyWorkThread()
{
while (true)
{
Thread.Sleep(1000);
}
}
}
}
When IsBackground is false it will keep your program open till the thread completes, if you set IsBackground to true the thread will not keep the program open. Things like BackgroundWoker, ThreadPool, and Task all internally use a thread with IsBackground set to true.
By the way. whenever my forms call the formclosed or form closing event I close the applciation with a this.Hide() function. Does that affect how my application is behaving now?
In short, yes. The entire application will end when the main form (the form started via Application.Run in the Main method) is closed (not hidden).
If your entire application should always fully terminate whenever your main form is closed then you should just remove that form closed handler. By not canceling that event and just letting them form close when the user closes it you will get your desired behavior. As for all of the other forms, if you don't intend to show that same instance of the form again you just just let them close, rather than preventing closure and hiding them. If you are showing them again, then hiding them may be fine.
If you want to be able to have the user click the "x" for your main form, but have another form stay open and, in effect, become the "new" main form, then it's a bit more complicated. In such a case you will need to just hide your main form rather than closing it, but you'll need to add in some sort of mechanism that will actually close the main form when you really do want your app to end. If this is the situation that you're in then you'll need to add more details to your question describing what types of applications should and should not actually end the program.
In this case, the most proper way to exit the application in to override onExit() method in App.xaml.cs:
protected override void OnExit(ExitEventArgs e) {
base.OnExit(e);
}
I have a published application in C#. Whenever I close the main form by clicking on the red exit button, the form closes but not the whole application. I found this out when I tried shutting down the computer and was subsequently bombarded by lots of child windows with MessageBox alerts I added.
I tried Application.Exit but it still calls all the child windows and alerts. I don't know how to use Environment.Exit and which integer to put into it either.
Also, whenever my forms call the FormClosed or FormClosing event, I close the application with a this.Hide() function; does that affect how my application is behaving?
From MSDN:
Application.Exit
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed. This is the code to use if you are have called Application.Run (WinForms applications), this method stops all running message loops on all threads and closes all windows of the application.
Environment.Exit
Terminates this process and gives the underlying operating system the specified exit code. This is the code to call when you are using console application.
This article, Application.Exit vs. Environment.Exit, points towards a good tip:
You can determine if System.Windows.Forms.Application.Run has been called by checking the System.Windows.Forms.Application.MessageLoop property. If true, then Run has been called and you can assume that a WinForms application is executing as follows.
if (System.Windows.Forms.Application.MessageLoop)
{
// WinForms app
System.Windows.Forms.Application.Exit();
}
else
{
// Console app
System.Environment.Exit(1);
}
Reference: Why would Application.Exit fail to work?
I know this is not the problem you had, however another reason this could happen is you have a non background thread open in your application.
using System;
using System.Threading;
using System.Windows.Forms;
namespace Sandbox_Form
{
static class Program
{
private static Thread thread;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
thread = new Thread(BusyWorkThread);
thread.IsBackground = false;
thread.Start();
Application.Run(new Form());
}
public static void BusyWorkThread()
{
while (true)
{
Thread.Sleep(1000);
}
}
}
}
When IsBackground is false it will keep your program open till the thread completes, if you set IsBackground to true the thread will not keep the program open. Things like BackgroundWoker, ThreadPool, and Task all internally use a thread with IsBackground set to true.
By the way. whenever my forms call the formclosed or form closing event I close the applciation with a this.Hide() function. Does that affect how my application is behaving now?
In short, yes. The entire application will end when the main form (the form started via Application.Run in the Main method) is closed (not hidden).
If your entire application should always fully terminate whenever your main form is closed then you should just remove that form closed handler. By not canceling that event and just letting them form close when the user closes it you will get your desired behavior. As for all of the other forms, if you don't intend to show that same instance of the form again you just just let them close, rather than preventing closure and hiding them. If you are showing them again, then hiding them may be fine.
If you want to be able to have the user click the "x" for your main form, but have another form stay open and, in effect, become the "new" main form, then it's a bit more complicated. In such a case you will need to just hide your main form rather than closing it, but you'll need to add in some sort of mechanism that will actually close the main form when you really do want your app to end. If this is the situation that you're in then you'll need to add more details to your question describing what types of applications should and should not actually end the program.
In this case, the most proper way to exit the application in to override onExit() method in App.xaml.cs:
protected override void OnExit(ExitEventArgs e) {
base.OnExit(e);
}
Basically I have a Login window which should close once the user logs in and show another window, for now I've just hid it(Form.Hide()) however I do not wish to take unnescesary system resources and I don't need the login window after I already logged in.
this is the code snippet where I perform the operation:
MainWindow w = new MainWindow();
TimeRegisterApI.Instance.Windows.Add(w.Text,w);
TimeRegisterApI.Instance.Windows[w.Text].Show();
this.Dispose();
Windows is a dictionary that stores references of forms with their title as the key.
TimeRegisterApi is a singleton.
Basically what happens is that my application exits after I login instead of just disposing the login window, when I want it to dispose(close and go to the garbage collector.)
I know that having the title as key might cause duplicate key entries but in my current design it's no problem.
You have to make your window form login as a modal form which parent is your mainform
it will allow you to wait an answer (like a savedialog) and return to your main window form)
this is your main form so you exist
ok I fixed the problem, basically what happens is that when the window that is run from program.cs at application.run(window) gets disposed it closes the program because it's the main window, I think it would be possible to do an e.cancel on the dispose event of this window, however I solved the problem by running the window in a new application.run like this:
from program.cs, relevant lines
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LoginWindow());
start();
}
public static void start()
{
if (TimeRegisterApI.isLoggedIn())
{
MainWindow w = new MainWindow();
Application.Run(w);
}
}
I have 2 forms: signin and control_panel. After signin done I'm hiding this form by this.Hide() function and same time I am making new object of control_panel form and showing it by newobj.Show();. But when I am closing directly control_panel form, I am seeing first form thread are still running. I am closing it by stop_debugging button. How will I close every threads or whole program exit simultaneously.
The thread for your first form is still running because you're only calling this.Hide. All that does is hide the form; it doesn't close it. Instead, you need to use this.Close, which will close your original form.
If you want to make sure that your entire application exits, and in the process close any forms that may still be open, you can use the Application.Exit method anywhere in your form's code.
EDIT: To expand on my last comment, you might want something like this in your Program.cs file:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SignInForm frmSignIn = new SignInForm();
if (frmSignIn.ShowDialog() == DialogResult.Yes)
{
//If the sign-in completed successfully, show the main form
//(otherwise, the application will quit because the sign-in failed)
Application.Run(new ControlPanelForm());
}
}
}
Create a FormClosed event in control_panel form property window of control_panel and write the following line as
private void control_panel_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
I've one MainForm window and from that user can press 3 buttons. Each of the button starts new Form in which user can do anything he likes (like time consuming database calls etc). So i decided to put each of the forms in it's own threads:
private Thread subThreadForRaportyKlienta;
private Thread subThreadForGeneratorPrzelewow;
private Thread subThreadForRaporty;
private void pokazOplatyGlobalne() {
ZarzadzajOplatamiGlobalneDzp varGui = new ZarzadzajOplatamiGlobalneDzp();
varGui.ShowDialog();
}
private void pokazRaportyKlienta() {
RaportyDzpKlient varGui = new RaportyDzpKlient();
varGui.ShowDialog();
}
private void pokazRaportyWewnetrzne() {
RaportyDzp varGui = new RaportyDzp();
varGui.ShowDialog();
}
private void pokazGeneratorPrzelewow() {
ZarzadzajPrzelewamiDzp varGui = new ZarzadzajPrzelewamiDzp();
varGui.ShowDialog();
}
private void toolStripMenuGeneratorPrzelewow_Click(object sender, EventArgs e) {
if (subThreadForGeneratorPrzelewow == null || subThreadForGeneratorPrzelewow.IsAlive == false) {
subThreadForGeneratorPrzelewow = new Thread(pokazGeneratorPrzelewow);
subThreadForGeneratorPrzelewow.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportow_Click(object sender, EventArgs e) {
if (subThreadForRaporty == null || subThreadForRaporty.IsAlive == false) {
subThreadForRaporty = new Thread(pokazRaportyWewnetrzne);
subThreadForRaporty.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportowDlaKlienta_Click(object sender, EventArgs e)
{
if (subThreadForRaportyKlienta == null || subThreadForRaportyKlienta.IsAlive == false) {
subThreadForRaportyKlienta = new Thread(pokazRaportyKlienta);
subThreadForRaportyKlienta.Start();
} else {
}
}
I've got couple of questions and i hope someone could explain them:
When i use Show() instead of ShowDialog() the windows just blink for a second and never shows. What's the actual difference between those two and why it happens?
When i use ShowDialog everything seems normal but i noticed not everything gets filled properly in one of the gui's (one listView stays blank even thou there are 3 simple add items in Form_Load(). I noticed this only in one GUI even thou on first sight everything works fine in two other gui's and i can execute multiple tasks inside those Forms updating those forms in background too (from inside the forms methods). Why would this one be diffrent?
What would be proper way of doing this? Tasks performed in each of those Forms can be time consuming and i would like to give user possibility to jump between those 4 windows without problem so he can execute what he likes.
The difference is with Modal and Modeless Windows Forms.
Modeless forms let you shift the
focus between the form and another
form without having to close the
initial form
Show() method is used for this purpose
Show() shows the new form, then returns. If this is all the thread is doing than the thread will exit, and that will destroy the form.
ShowDialog() shows the form, and then begins running a message pump, until the form is hidden or destroyed, ShowDialog() doesn't return, so your thread keeps running.
If You mean for these forms to each behave like a separate application window. then you could also use Application.Run() after form.Show() to run a message pump for the form on that thread. The drawback to doing it this way, is that when any one of your forms is closed, it might end up taking down the whole process because of the way WM_QUIT is handled.
But other than the way you would deal with closing down your application, Form.ShowDialog() is very much like Form.Show() followed by Application.Run(). The conditions that cause the message pump to exit are a bit different between these to, so you would choose one or the other mostly based on how you want to your application to handle closing one of your forms.
You should put the time-consuming tasks in their own BackgroundWorker threads. Keep all of the forms in the main thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
1: Show() is not blocking, that is it shows the window and then returns. Afterwards, the varGui variable goes out of scope and is finalized by the garbage collector => disappears.
2: You'd need to show the updating code to get a definite answer, but as you can only update the contents of a form when running in the thread that created the form. Doing it otherwise is unreliable, so is the usual culprit when form updates don't work. In a method of a form class, call:
if (InvokeRequired) {
.Invoke(..); // call back this same method on the right thread
} else {
// dowork
}
to manage the UI.
3: The proper way is what Jake wrote: use one thread for all GUI stuff and BackgroundWorker threads for, well, background work.