I have such form
public ManagerMainForm()
{
InitializeComponent();
...
}
So, if I run the app MainForm open and all is ok, but I need to add one new form as a popup.
public ManagerMainForm()
{
InitializeComponent();
....
var dialog = new ValidationConfigDialog();
dialog.ShowDialog();
...
}
And now this ValidationConfigDialog (Form) opening faster then ManagerMainForm and because of ShowDialog it's stop opening ManagerMainForm until I close it.
So, what I need? I would like to have like a OnFormLoaded event (maybe kind of callback) that notify me that ManagerMainForm has already completely loaded and visible and I can run another correspond process.
So, question is - How to get such kind of event or how to implement such logic, that allow to start process after form was loaded?
There is a nice MSDN page that tells you the order of events that are raised when a form is opened. The order is:
HandleCreated
BindingContextChanged
Load
VisibleChanged
Activated
Shown
Since your problem is that the second form is showing too early, I suggest you pick the latest event to execute the code that shows the second form. If that doesn't work for some reason, try the second latest, and so on.
Example:
Shown += (sender, args) => {
var dialog = new ValidationConfigDialog();
dialog.ShowDialog();
};
Related
I have several modeless Forms with grids to show data in a MDI Windows Forms app (Form1 in example code). Each of these Forms has a button that opens another Form as modal using ShowDialog (Form2 in example code), which allows editing the data shown in Form1. These modal forms have a Cancel button that closes the form without saving changes by setting DialogResult to Cancel.
I want to implement a timer that closes all forms after a certain time has elapsed from user login into the app. The problem arises if the timer triggers while a modal Form is open.
public partial class Form1 :
{ //Constructor ommited for brevity
private void btnEditData_Click(object sender, EventArgs e)
{
var form2 = new Form2();
timer1.Tick += (_, __) =>
{
form2.DialogResult = DialogResult.Cancel;
this.Close(); // this executes before form2.ShowDialog returns
};
timer1.Interval = 5_000;
timer1.Enabled = true;
form2.ShowDialog();
reloadData(); // here Form1 is already disposed because Close
// has been called on it. An exception is thrown as a consequence
}
private void reloadData()
{
if (this.IsDisposed)
// simulate using a disposed form
throw new ObjectDisposedException(this.Name);
}
}
My intention would be to somehow schedule the call Form1.Close() after form2.ShowDialog() has returned and the btnEditData_Click method has finished, so that there would be no danger of using a disposed form.
EDIT
After seeing your code, I'd suggest to introduce a third option in your Tick event handler that would be used to decide if you have to close the form. For example, Abort.
timer1.Tick += (_, __) =>
{
form2.DialogResult = DialogResult.Abort;
};
if (form2.ShowDialog() == DialogResult.Abort) Close();
else reloadData();
First thought: keep it simple and keep it clean. You don't have to keep track of your open forms, in an MDI application there is MdiChildren property of the parent form that will give you all the forms.
Then, to handle the closing part, you can use existing functionalities in .Net.
A difficult approach is using P/Invoke. You load Windows DLLs and use their functions to enumerate through all your forms and close which one you want. You can also simulate a click on Cancel button. You have to start with EnumWindows function (to identify the forms) and EnumChildWindows for form's children. I like this option because you have full control of your forms and controls, but can give you headaches if not familiar with the concept.
You can have a look at FormClosing event and subscribe to it. This event fires before the form is closed and you can make the clean up using it.
Using OOP - inheritance and override. Either you create a base form with custom close function that does the cleaning (and then inherit all your forms through it), or override form's close functions to achieve your goal.
i got application, it shows 3 forms: log window, status window, and option window, option window calls some other forms and some of these forms are required to be called using ShowDialog() to return dialog result value for further decision making.
Using ShowDialog() raises problem, cause form called by that method excluding other forms from being accessible.
So my problem is i would like to be able to make atleast log window accessible no matter how much other forms has been called. Is there a way to make log window to independent form other forms, or could it be taken over by form called as last?
EDIT:
I failed to mention that the behaviour provided by ShowDialog() is quite usefull in my app and that i only lack ability to free that one or two forms from being locked. Switching to Show() is not option I'm considering as best while other forms, that are parent to form called by ShowDialog() are required to be still locked.
You'll have to make a choice between the two.
Use ShowDialog(), so that your parent form pauses execution, and only resumes when the second form is closed, or
Use Show(), so that your parent form continues execution after displaying the second form.
If you want to take some action, or read values from the second form when it's closed, then subscribe to its Closed event before you show it.
Let's assume your second form has a "First Name" TextBox, and a property to return that value:
public string FirstName
{
get { return yourFirstNameTextBox.Text; }
}
In your first form, you can subscribe to an event to take some action when the event occurs, like this:
var f2 = new SecondForm();
f2.Closed += (s, e) => MessageBox.Show(f2.FirstName);
f2.Show();
Now the user can continue on their way with both forms, and when the second form is closed, a message box will display the value of the "First Name" TextBox.
You'll probably want to do something more meaningful than this. Instead of displaying a message box, you could update a field on the first form, or take some any other action or set of actions that you want.
f2.Closed += (s, e) =>
{
MessageBox.Show(f2.FirstName);
nameLabel.Text = f2.FirstName;
// another action
// yet another action
};
So I now modeled your situation and found solution:
Use Show() instead ShowDialog() for dialog.
Write some code in the dialog to close it window after press the button (Ok, Cancel etc.). Because auto-closing works with ShowDialog only. But you don't need to set DialogResult manually.
At the Options form subscribe to FormClosed event to get DialogResult. For example:
dlg.FormClosed += (o, a) => { this.Text = dlg.DialogResult.ToString(); };
Handle Activate event of Options form to prevent focusing on parent window when dialog is opened:
if (dlg != null) dlg.Focus();
This solution has some difference with system behaviour of ShowDialog, but it works good.
I have 2 forms ...when i start the application..and use the close "X" from the title bar the entire application closes...now when i select an option from the 1st form in my case it is a button "ADD" as its a phonebook application..it goes to the 2nd form as i have used 1stform.hide() and 2ndform.show()...now when i do "X" from the title bar it doesnt shutdown completely as the 1stform is not closed....how to program it in such a way tht any stage the entire application should close
Your first form is set as the startup form. That means whenever it gets closed, your entire application is closed. And conversely, your application does not close until it gets closed. So when you hide the startup form and show the second form, the user closing the second form does not trigger your application closing because they have only closed a secondary, non-modal dialog.
I recommend changing your design so that the startup form is also the main form of your application. No sense trying to work around built-in functionality that can actually be useful. You want the application to quit when the main form is closed, no matter what other child forms are opened.
But the quick-and-dirty solution in your case is to make a call to Application.Exit. That will close all of the currently open forms and quit your application immediately. As I said just above, I don't so much recommend this approach because having to call Application.Exit from every form's FormClosed event handler is a sign that something has gone seriously wrong in your design.
If the single startup form paradigm doesn't work out for you, you should look into taking matters into your own hands and customizing the Main method in your Program.cs source file. See the answers given to this related question for some ideas on how that might work for you.
What you can do is to use the Form's FormClosing event, and add the following code:
Application.Exit();
This will stop the entire application, and close all windows. However, if a background thread is running, the process itself will survive. In this case you can use:
Environment.Exit();
Add a Application.Exit on every forms's Closing event
like this:
Create an closing event handler first
private void Form_ClosingEventhandler()(object sender, CancelEventArgs e)
{
//Perform any processing if required like saving user settings or cleaning resources
Application.Exit();
}
then bind this event to any form you create.
//Where you create new form and show it.
Form1 frm= new Form1();
//set other properties
frm.Closing += new EventHandler(Form_ClosingEventhandler);
Form2 frm2= new Form2();
//set other properties
frm2.Closing += new EventHandler(Form_ClosingEventhandler);
Surely you don't want to shut down the entire application after the user adds a phone number? You just need to make sure that your main window becomes visible again. Write that like this:
private void AddButton_Click(object sender, EventArgs e) {
var frm = new AddPhoneNumber();
frm.StartPosition = FormStartPosition.Manual;
frm.Location = this.Location;
frm.Size = this.Size; // optional
frm.FormClosing += delegate { this.Show(); };
frm.Show();
this.Hide();
}
I have a form in a Windows form application that I want to display on top of a main form, close it, and then immediately show a dialog box using MessageBox.Show(). But the first form is still showing when the message box is shown, and it does not disappear until I click OK on the message box. I tried waiting to show the message box in an event handler for the form's VisibleChanged event and even calling Refresh() on both the form and the main form. Is there a way I can determine when the first form has fully disappeared before displaying the message box?
Edit:
Here is some code that demonstrates how the forms are being shown.
static class Program
{
// The main form is shown like this:
static void Main()
{
Application.Run(new MainForm());
}
}
public class Class1
{
// _modalForm is the first form that is displayed that won't fully go away
// when it is closed.
ModalForm _modalForm;
BackgroundWorker _worker;
public Class1()
{
_modalForm = new ModalForm();
_worker = new BackGroundWorker();
_worker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted
}
public void Method1()
{
_worker.RunWorkerAsync();
// The first form is shown.
_modalForm.ShowDialog();
}
// This code runs in the UI thread.
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_modalForm.VisibleChanged += new EventHandler(_modalForm_visibleChanged);
_modalForm.Close();
}
void _modalForm_visibleChanged(object sender, EventArgs e)
{
// When the message box is shown, the other form is still visible
// and remains so until I click OK.
MessageBox.Show("The other form was just closed.");
// Note: I originally tried to use the FormClosed event instead of
// VisibleChanged. Then I tried Deactivate, in attempt to use an event
// that occurred later thinking that might do the trick. VisibleChanged
// is the latest event that I found.
//
}
I'll guess that you are running your code on Windows XP or Vista/Win7 with Aero turned off. Closing a form does not make the pixels on the screen disappear instantly. The Windows window manager sees that the window for the form got destroyed and that this revealed parts of other windows underneath it. It will deliver a WM_PAINT message to let them know that they need to repaint the parts of the window that got revealed.
This will not work properly if one or more of those windows isn't actively pumping a message loop. They can't see the WM_PAINT message. They won't repaint themselves, the pixels of the closed form will remain on the screen.
Find out why these windows are not responding. Hopefully it is your window and the debugger can show you what the UI thread is doing. Make sure it isn't blocking on something or stuck in a loop.
After seeing the edit: there's indeed blocking going on, of a different kind. The MessageBox.Show() call is modal, it prevents the VisibleChanged event from completing. That delays the closing of the form.
Use System.Diagnostics.Debug.WriteLine() or Console.WriteLine() to get diagnostics in a Window Forms app. You'll see it in the Output window. Or simply use a debugger breakpoint.
The Form.FormClosed event is raised when the form completes closing. At this point, all Form.FormClosing event handlers have been run, and none of them canceled the close.
Form.FormClosed replaced Form.Closed (which is deprecated) in the .NET 2.0 framework.
Form.Closed Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed(VS.71).aspx
I have a Dialog with showing some information about an object. I want to close this Dialog to show the same dialog but now with the object's sibling. It is a complex dialog that loads different components depending on the object assigned, I cant just change the reference to another object
I tried launching the new one in the Closed event, but the former hasn't disapear from the screen and keeps showing. Also tried a static method that is called whithin the Dialog, passing the same Dialog as a parameter, so it close the dialog 'dialog.Close()' and opens a new one with the new object to show. But still the former one keeps opened behind.
Is there a way to accomplish that, closing the first window and opening the second?
( THIS IS The Static approach, the window passed by parameter doesn't close until the new one created is closed)
// From the Dialog try to launch the second one closing this.
private void btnSibling_Click(object sender, EventArgs e)
{
SwitchToSibling(this);
}
private static void SwitchToSibling(SiblingDialog window)
{
try
{
double id = 0;
id = window.SelectedSibling();
if (id != 0)
{
// Get's the same Parent so to the new Dialog
Control owner = window.Owner;
window.Close();
Sibling sibling= Sibling.Get(id);
SiblingDialog.ShowSibling(sibling, false, owner);
}
}
catch (GroupException ex)
{
MessageBox.Show(ex.Message);
}
}
I had the same problem, and after a lot of troubleshooting I managed to solve it in an entirely different way: I first wait for the Forms.Application.LeaveThreadModal event to occur, and then I wait for the next Forms.Application.Idle event to occur. By that time the first dialog has completely disappeared, so it is possible to launch the second dialog without any problems.
Waiting only for the idle event, or only for leave-thread-modal event, or for both events in the opposite order, will not work.
CAUTION: Waiting only for the idle event APPEARS to work, but only for as long as the activation of the second dialog is done by clicking a button of the first dialog with the mouse. If you trigger the button by pressing the mnemonic key of that button on the keyboard, the second dialog appears above the first dialog! You have to go through the sequence I described in order to avoid this!
After thinking about it a bit more, it seems to me that my solution is kind of "magic", which means that it may stop working in a future release of the dotnet framework, so I think I will ditch it and follow the advice of Mike Hoffer, which, as far as I can tell, is essentially the same as the answer that jmayor gave for himself and marked as accepted. (The truth is that Mike Hoffer's answer is a bit hard to follow.)
Without knowing the specifics inside the Sibling and SiblingDialog classes, sure you can. The only constraint would be that if you close the window that is the application's main window, the application will exit.
You could, for instance, provide a method like so:
private static void CloseAndShow(Form formToClose, Form formToShow)
{
formToClose.Close();
formToShow.Show();
}
That would close formToClose and show formToShow.
If you've set the owner for the first dialog, and you know its type, you should be able to solve this problem as follows:
Write a custom event on the dialog's
owner.
When the user clicks the close
button, invoke the event.
Do not
close the dialog from the button.
Have the owning window close the
dialog when the event handler is
invoked. Then have the owning dialog
show the sibling dialog.
An extension of Fredrik Mork's answer, that addresses the fact the closing form may be the form controlling the exit status of the program.
private static void CloseAndShow(Form formToClose, Form formToShow)
{
Application.Run(formToShow);
formToClose.Close();
formToShow.Show();
}
Application.Run tells the program to exit when the form passed to it closes
As it seems that you are setting the owner of the dialog, you can try to use owner.BeginInvoke() in the FormClosed() event handler in MyForm class. :
public partial class MyForm : Form
{
static int count = 0;
public MyForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
public static void ShowMyDialog(MyForm form, IWin32Window owner)
{
count++;
form.Text = "My ID: " + count;
form.ShowDialog(owner);
}
delegate void MyDel(MyForm form, IWin32Window owner);
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
MyDel del = ShowMyDialog;
MyForm mySecondForm = new MyForm();
this.Owner.BeginInvoke(del, mySecondForm, this.Owner);
}
}
The only way I Could find a way around is by calling my dialog from a static method( using sort of a singleton Pattern) , then using a static variable to flag when the Dialog needs to be reopened. So when a dialog execution is ended inside the static method it checks if it needs to be reopened.
Otherwise I don't see a possible way.