Invoking several methods after ordering the program closed - c#

I've got a WinForm Application that connects via Net.Sockets to another program.
When it gets closed per X or ALT+F4 or whatever, several routines should be processed and I need to keep the network connection until they're done.
I thought an Application.ApplicationExit Handler would do the trick, but as soon as I give the order the network connection is dead. Other important stuff can't be done.
My Form is closed instantaneously too, and I need that one a little longer.
Is Application.ApplicationExit the right tool for the job?
I put that in my Form Class that App.Runs from the Main method which is located in a different class.

You could use the Closing event of the form. It is called before the form is closed.

If you are having an open window, there are the event-handler Closing and Closed. The Closing-event is fired as soon as you click 'X', for example. Inside the method you can even decide, whether to close the window or not.
Provide an event-handler like
private void Form1_Closing(object sender, FormClosingEventArgs e){
// persist until everything is done
}
and associate it with the event
Form1.Closing += Form1_Closing;
See MSDN for documentation.

Related

C# Form doesn't close [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
In my Windows form the application doesn't exit even though I execute this.Close();
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
If I try disposing it directly it just crashes.
In my main class I open an instance, which is what i'm trying to close. Before it didnt't want to close, it didn't open.
This is not my main class.
FIX: Replacing "show()" with "showDialog()" fixed it.
Remarks from Form.Close()
When a form is closed, all resources created within the object are
closed and the form is disposed. You can prevent the closing of a form
at run time by handling the Closing event and setting the Cancel
property of the CancelEventArgs passed as a parameter to your event
handler. If the form you are closing is the startup form of your
application, your application ends.
The two conditions when a form is not disposed on Close is when (1) it
is part of a multiple-document interface (MDI) application, and the
form is not visible; and (2) you have displayed the form using
ShowDialog. In these cases, you will need to call Dispose manually to
mark all of the form's controls for garbage collection. NoteNote
When the Close method is called on a Form displayed as a modeless
window, you cannot call the Show method to make the form visible,
because the form's resources have already been released. To hide a
form and then make it visible, use the Control.Hide method. Caution
noteCaution
Prior to the .NET Framework 2.0, the Form.Closed and Form.Closing
events are not raised when the Application.Exit method is called to
exit your application. If you have validation code in either of these
events that must be executed, you should call the Form.Close method
for each open form individually before calling the Exit method.
This clearly states that the form should close and application should end unless you do something else we cannot see in your example.
The Close method is a Form's method, it closes the Form, this closes the Application instead :
// Close everything down.
Application.Exit();
As you can see the Application Class doesn't have a Close method, it has an Exit method instead, the this.Close() closes the concerned Form, but keeps the application running.

Form gets disposed on Hide()

I have a C# WinForms application running on .NET Framework 4.0.
When the user is inactive for a certain period of time, I want it to hide all the displayed forms and show an icon in the notification area. When the user clicks that icon, a login form appears and if the credentials are valid, it opens the exact forms that were open before.
To do this, I store the list of open forms in a List of Form objects and hide them, like this. This method is called by a Timer:
private void LogOut()
{
foreach (Form form in Application.OpenForms)
if (form.Visible)
{
GlobalVariables.formList.Add(form);
form.Hide();
}
}
When the credentials are validated, I try to make the forms visible again, like this:
//Show the previous forms.
foreach (Form form in GlobalVariables.formList)
form.Visible = true;
//Clear the forms list.
GlobalVariables.formList.Clear();
If I only have the MainForm open when I hide the forms, it shows it back fine when logging back in. If I have any other forms open (which are opened using ShowDialog() from the MainForm), the program will crash on form.Visible = true; and give me the following error message:
ObjectDisposedException was unhandled
Cannot access a disposed object
How can I fix this problem? An alternative way of doing what I'm trying to achieve would also be great.
Please note that using a try - catch block to determine if the form has been disposed and just relaunch the form is not an option as the user may have unsaved input in the hidden forms.
I couldn't manage to find anything related online in over 3 hours of search so any help would be much appreciated!
EDIT: After trying various things, I have noted that the problem only occurs on forms I have opened forms using ShowDialog(). If I only have forms opened using Show(), everything works fine.
However in my case, using Show() is not an option because I cannot have the user click on things in the parent form. Hiding the parent form is not an option either as he needs to see information in the parent form.
Clearly hiding a form is more impactful than you counted on. Your code was involved in a security review that Microsoft conducted on Winforms. Very thorough, not often visible in the way it behaves but very visible in the source code. One rule is imposes is that a user should never lose control over the application.
A dialog is very troublesome that way. The core problem is that ShowDialog() creates a modal window that disables all the other windows. That creates an opportunity for malware, very easy to take advantage of, all it has to do is hide a dialog and you snookered the user. There isn't any way that the user can gain control of the app again. The one window that was enabled is hidden with no way for the user to re-activate it again. All the other windows are disabled so trying to click on them, or their taskbar button, will not have any effect. All that's left is for the user to use Task Manager to kill the app. And if the user account is locked down then that's not an option either.
I can hear you sputter by now: "But, but, it is my code that hides the dialog, not malware!" That's not the way it works in Windows, there's no way to tell that it actually was your code that did it. Not only because it could be injected code, it doesn't even have to be code that runs in your process. Any code can do it, it is part of the winapi.
So there's a specific counter-measure against this built into Winforms, it will automatically close a form if it is hidden while operating in dialog mode. Which of course has a big impact, code that was written after the ShowDialog() call will now run. Anything is possible, but a sure-fire mishap in your case is that this disposes another window and an attempt to revive it will die.
The rough guidance here is that you are doing it wrong. You are trying to build a security system on top of one that's already highly secure and heavily tested. And it is very risky, handling passwords yourself is a very good way to make the overall system much less secure. The average user will of course favor picking the same password as he used to login to Windows. Makes it much easier for an attacker to harvest that password.
Call LockWorkStation() instead.
After many hours of trial and error, I found out what the problem was.
My understanding of modal forms was that code would continue executing in the parent form only after the modal form was closed. In fact, the specification found on MSDN states:
A modal form or dialog box must be closed or hidden before you can continue working with the rest of the application.
This introduced a subtle bug in the way I handled the forms. This is the code I used to display the forms:
using (var theForm = new CreateInvoice())
{
theForm.ShowDialog();
if (theForm.Updated)
{
GetInvoiceStatus();
}
}
The using statement disposes of theForm as soon as the statement exits. Normally, this works perfectly fine as it would be called only when the user closes theForm. However, because ShowDialog() permits the parent form to continue its work when it is hidden, this meant that the code actually exited the using statement, which effectively disposed of theForm, resulting in my error.
Testing, it seems that Hide()ing a modal dialog - closes it. It actually triggers the FormClosing event.
Tested like this: (Also, see this answer.)
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
Hide();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
MessageBox.Show("Closing");
}
EDIT
I noticed this actually doesn't solve the mystery, just adds more information. Here's another piece of information: When you're setting Visible to true - you're not showing it modal again. This time it's equivalent to Show().
One suggestion to the design: instead of saving forms(views), you should save the data that the form holds(Model) and destroy the form. When you need the form again, create it back with the data(model). First, this can resolve this mysterious dispose problem, second, each form will need GDI resource, which are limited, if two many forms, you'll encounter the memory and GDI problems.
As how to do this, please refer the MVC or MVP design pattern.
BTW my guess on this problem: when you make the form visible, it will try find its parent, but its parent may be already disposed. I encountered this problem once, it throws the object disposed exception.

How to delete file, then user closes program in WPF?

I know full path of file var temp_file = Path.Combine(_directoryName1, "temp.ini"); which need to be deleted in the end of program working. How could I do this ? As I know it is possible to realize via OncloseEvent(). In addition, I dont know exatly how user will close application via alt+f4 or via buttons.
So far, I have tried to use this code below from almost the same question How to override onclose event on WPF?
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
//do my stuff before closing
base.OnClosing(e);
}
And I have added it in App.xaml.cs but it doesn't work. VS2013 says that he don't know such method base.OnClosing(e);
Is there any mistake or another way out?
Window.Closing is for a specific Window. That's probably not what you want in any case, because the Closing event can be cancelled. Window.Closed is likely a better choice.
To run something when the program is closed -- not tying yourself to a window -- you should subscribe to the Application.Exit event instead.

What is the best way to call a method right AFTER a form loads?

I have a C# windows forms application. The way I currently have it set up, when Form1_Load() runs it checks for recovered unsaved data and if it finds some it prompts the user if they want to open that data. When the program runs it works alright but the message box is shown right away and the main program form (Form1) does not show until after the user clicks yes or no. I would like the Form1 to pop up first and then the message box prompt.
Now to get around this problem before I have created a timer in my Form, started the timer in the Form1_Load() method, and then performed the check and user prompt in the first Timer Tick Event. This technique solves the problem but is seems like there might be a better way.
Do you guys have any better ideas?
Edit: I think I have also used a background worker to do something similar. It just seems kinda goofy to go through all the trouble of invoking the method to back to the form thread and all that crap just to have it delayed a couple milliseconds!
I would use Form1_Shown()
Use the Shown event. It seems to suit what you need, and will only display the first time the form is shown.
Form f1 = new Form();
f1.Shown += new EventHandler(f1_Shown);
public void f1_Shown(object sender, EventArgs e)
{
// Show dialog in here
}
Try the "Shown" event:
Form.Show Event
Using a Windows.Forms.Timer is a good, stable, well-known, and easily understood technique for doing what you want. I would avoid any other timer objects.
The form's Shown event works well.
Overload / override the Show method. (My preferred technique for greater control.) In this method, I would do the checking needed. When ready, I would call the base.Show method, then do any other processing, such as message boxes, prompts, logging, or whatever.

How to dispose of variables in windows close button

I have a windows forms application, where I have declared some static variables.
On the click of exit button, I have disposed of some datatable which i have declared static.
Many a times the user instead of clicking the exit button, will just exit the windows application by clicking the X button on the left corner top.
What should be done to ensure that even if the user clicks the X button, everything is disposed of properly.
Thanks
Regards
Hema
This question has some good descriptions of events that you can hook into to detect when a application is exiting.
Does Application.ApplicationExit event work to be notified of exit in non-Winforms apps?
Just add a delegate function to the Closing event of the form.
this.Closing += this.MyForm_Closing;
You can also use the Closed event of the form if you'd prefer it gets called after the form is closed.
You can add an event handler to dispose your variables when the form is closing.
private: System::Void myDialog_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) {
// Dispose your static variables here
}

Categories