I have a method RunForm() that runs a modal dialog performing some task:
static void RunForm() {
SomeForm form = new SomeForm();
Application.Run( form );
}
I want to call RunForm() multiple times from the STAThread entry point:
[STAThread]
static void Main() {
RunForm(); // Run form once
RunForm(); // Run form twice
RunForm(); // Run form etc.
}
At some point, the form calls "Close()" on itself and unfortunately the application's thread exits and any subsequent call to RunForm() exits immediately...
But if I close the modal dialog manually by clicking the top-right red cross button, the subsequent calls to RunForm() work correctly (i.e. the application's thread is still running somehow).
How can I automatically run multiple modal dialogs in a sequence?
(and what is the difference between a manual close and a programmatic call to Close()?)
Application.Run(ApplicationContext) is more likely a better fit for your usage of multiple forms by running just once this method and by handling the multiple open/closing forms from your application context implementation (as it is described in the link)
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'm trying to make a new form appear when I click on a label. I'm using Windows Application Forms.
Here's the code:
private void label1_Click(object sender, EventArgs e)
{
Form parpokeru = new Form();
parpokeru.Show();
parpokeru.ShowDialog();
}
When I click on the label, a error appears (Unhandled exception has occurred in your application...). Can anyone tell me how to fix it?
Call .Show() or .ShowDialog(). Not both.
Show() will display your second form, while still allowing the user to access the first form.
ShowDialog() will display your second form as "modal". Execution of code in the first form stops while the second form is open (at least on the main thread.. for example, timers will continue to run), and the user will not be able to access your first form while the second is open.
When you call the Show method your form is shown on video like another window and the code returns immediately from the call. So your code continues and all the forms of your application are available for the user interaction. It is calledd a modeless dialog
On the contrary, ShowDialog is a blocking call. The code doesn't return from this call until something happen inside the called form that terminates the visualization of the form. As an example comes to ming a call to the methid Hide or a click on a button with its DialogResult property set to something different from DialogResult.None. At this point the code from ShowDialog returns and the normal processing continue. While the code is blocked inside the ShowDialog the application is blocked and the user cannot interact with other forms or menus or whatever is displayed on video. It is called modal dialog
Another difference is ShowDialog returns value (a DialogResult enum value) that can can be used to determine how the user closed the form (DialogResult.Cancel, DialogResult.OK), also ShowDialog does not call the Dispose method at closing time. This will allow to retrieve property from the Modal Dialog like user inputs for further processing.
I cannot imagine what happen in the internal processing of your form if, after a modeless call to Show you call immediately a ShowDialog on the same form instance. However, an exception is really the minimum to expect from this code.
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 am displaying dialog on the main form, now one for loop is working behind but when that dialog will displayed code execution will be stopped, but I don't want to let stop the execution of the code, is any other any way to do that ?
EDIT: I am using now thread to do that and my code is like
Thread t;
private void StartParsingByLoop()
{
t = new Thread(new ThreadStart(RunProgress));
t.Start();
for (int i = 0; i < dialog.FileNames.Length; i++)
{
cNoteToParsed.AllContrctNotesFilePath.Add(dialog.FileNames[i].ToString());
}
cNoteToParsed.ParseContractNote();
if (cNoteToParsed.NOfContrctNoteParsed > 0)
LoadTransactionsInDataGridView();
t.Abort();
}
private void RunProgress()
{
frmProgress progressForImportingTran = new frmProgress("Importing Transactions", "ok");
progressForImportingTran.ShowDialog();
}
Now I have problem is that the dialog that shows the progress does not behave like dialog and gives access of the main form and if we try to access the main form then dialog goes to hide. And I dont want to make the dialog be hide.
You can let a different thread handle the loop.
Response to edit: Can you provide more details, perhaps some code? what is the loop doing? what form do you display?
(this answer is based on the assumption that we are taking about a winforms app)
Show the form using the Show method, rather than ShowDialog. By passing a reference to the main form, the dialog will stay on top of the main form even if it is not modal:
TheDialog dialog = new TheDialog();
dialog.Show(this);
Note though that the user can still interact with the controls on the main form, so you might want to disable some controls, depending on your scenario.
You state in your question that there are requirements that prevent you from using threading for this. This kind of requirement strikes me as odd, and it is a pity because this is one of the typical scenarios when you would want to use some sort of asynchronous construct. By performing heavy work on the UI thread, you get some drawbacks, including:
The UI will not be responsive - if you want to allow the user to cancel the work by clicking a button, that will be tricky to achieve in a robust manner.
The UI will not redraw properly since the UI thread is busy performing other work.
Do not use ShowDialog() but Show() to display the dialog windows. Show() will immediately return to the caller whereas ShowDialog() will hold the execution. Note that when using Show() your dialogs won't be modal anymore.
OK, so you don't need modal dialog, you need a mechanism for your user not to be able to select your main form while processing is enabled.
Modal dialog doesn't mean that execution is stopped - it just happens somewhere else.
There are several methods to do this, and you ruled out new thread creation (don't know why, it would solve it elegantly). If don't use thread, you'll have another problem - your processing should be done in CHUNKS and every little while you'll have to do something like Application.DoEvents() to enable your application to process messages and not be frozen to the user.
So, if you can create a method in the main form that shows your 'please wait' dialog which will perform some work and later do some more until is finished, you can do this:
create a new form (wait dialog)
start a timer inside of it and wire timer to the PARENT form
timer interval should be 1
ShowDialog() the form
on timer event do small amount of work (don't allow it to go more then 1/10 of seconds)
Can you do that?
Anyway:
task can't be split into small workable pieces
you can't use threads
you want your UI to be responsive
PICK 2. You can't have all 3 in Winforms.
In my application I want to show a login form first and then the main form if the login has been successful. Currently I'm doing it something like this:
var A = new LoginForm();
if ( A.ShowDialog() == DialogResult.OK )
Application.Run(new MainForm());
But then I started wondering - what's the point of the Application.Run()? Why not just do (new MainForm()).ShowDialog() as well? What's the difference? And what would be the correct way to achieve what I want?
Application.Run(Form) starts a message loop on the current thread and displays the specified form. The message loop enables the form to receive Windows messages (eg, key presses, mouse clicks, paint invalidations) to allow it to appear responsive and have interaction with the user. When you call ShowDialog() on a Form instance, it actually does a similar thing and creates a modal message loop for the form on which ShowDialog has been called.
There is not much difference between the two calls. Application.Run does add some extra event handling enabling you to do some tidying up of resources when the main form is closed (see Application.ThreadExit).
The recommended way to start WinForms applications is using Application.Run, but I suspect this is more of a convention than a rule. The biggest reason to use Application.Run is if you want to open multiple non-modal forms. You can do this using:
new Form().Show();
new Form().Show();
Application.Run();
You could not achieve this using the ShowDialog() method as one of the forms would have to be modal.
As for your question of how to show a login form and then the main form if the login is successful, I think what you have is fine:
if (new LoginForm().ShowDialog() == DialogResult.OK)
{
Application.Run(new MainForm());
}
The alternative is to do the plumbing yourself and open an instance of MainForm in the closing event of the LoginForm if the login was successful.
From MSDN:
This method adds an event handler to
the mainForm parameter for the Closed
event. The event handler calls
ExitThread to clean up the
application.
http://msdn.microsoft.com/en-us/library/ms157902.aspx
From my testing, I noticed this main difference:
When Application.Run is used, the form's Close button (red X) returns DialogResult.None; however, when ShowDialog is used, the Close button produces DialogResult.Cancel.
Does this matter to you? In my code, I was testing for DialogResult.Cancel to determine the exit code of my application. That was broken when the red X was used to close the form. I now test for DialogResult.OK to indicate a successful exit.
return myForm.DialogResult == DialogResult.OK ? 0 : 1;
One key difference is that ShowDialog is usually a modal Dialog. If you wanted to create a user-friendly toolset, you would not want it to be comprised of modal dialog boxes.
Also, Application.Run() accepts more than just a form. It has a few overloads.
As for your application, I do not think it matters much. Application.Run makes sense to me because it denotes the start of your actual Application.
The documentation of the overload
public static void Run(
ApplicationContext context );
has a neat example with a different approach that involves two forms as well.
For a more concerete example of a difference:
If your main form is an MDI form, then the behavior on clicking the close button (the 'x' in the upper right, or Alt-F4) is different depending on which method you use to show the form.
With Application.Run(mainForm), the closing event of the child forms run, then the main form's closing event runs.
With mainForm.ShowDialog, the closing event of the main form runs, and the closing event of the child forms do not run.
Application.Run() is for the start of application while MainForm is part of the application and MainForm()).ShowDialog() used to display it only.
Application.Run() is the entry point for your Application. same as Main() method is for some class or ApplicationStart() for a WebApplication
Application.Run() has different overloads, one of which is without parameters. That Method starts application without an initial form.
From my testing I notice that using Application.Run buttons with DialogResult does not close the form (OnFormClosing is not hit) compare to ShowDialog in which the buttons with DialogResult hit OnFormClosing and the close the form.