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.
Related
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();
};
I have some code meant to open a new windows form when one is closed, and yet I get nothing, no error.
I've tried a few different methods for opening a new form on a Form.FormClosed event.
This is the code I have right now:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Form1 myForm = new Form1();
myForm.Show();
}
But yet I get no error, nothing.
I'm expecting for a new windows form to be opened when I close another one.
Any help would be appreciated, thanks!
The problem is that as soon as the first Form1 instance closes, your application shuts down and exits because the application message loop is defined with the initial Form instance, and it is just waiting for events on that form until it closes. On closing, the application will exit, opening a new form doesn't stop this process.
You need to adjust the Main() method in Program.cs to look something like this:
[STAThread]
static void Main()
{
// ... Application configuration as required here
new Form1().Show(); // The first form instance is now no longer bound to the Application message loop. Start it before we begin the run loop
Application.Run(); // Don't pass in Form1
}
Your original code should now work. I might add however, this is not a great user experience. Carefully consider what you're trying to achieve, and perhaps consider alternatives - do you just need a "reset form" button? Or is the primary goal to prevent a user from closing the application? If the latter, you can remove the Close icon altogether.
Perhaps something simple to get your going forward.
private Form1 myForm = new Form1(); //Declare the form as a private member variable
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
e.Cancel = true; //Cancel the closing so this object stays alive
this.Visible = false; //Hide this form
myForm.Show(); //Show the next form
}
Please note #pcdevs comment. You'll need a way to indicate the form is being closed/application quiting vs progressing to the next step/form. You might want to look at some CodeProject articles about "C# Winform Wizards", those sequential dialog prompt apps...
I recently created a simple custom message-box. Its just another form called using ShowDialog().
I have two buttons YES / NO that sets the DialogResult value then Hides the form using this.Hide().
However, when I do this, the entire application closes. This does not happen when using this.Close(). The reason why I chose using Hide is because the response appears to be faster. When using Close, the Message Box Form lingers for 2-3 seconds before closing.
Below is some code:
public static void Init()
{
if (_instance == null)
{
_instance = new MQMessageBox();
_instance.MQButtonYes.Click += MQButtonYes_Click;
_instance.MQButtonNo.Click += MQButtonNo_Click;
}
}
public static DialogResult Show(string caption, string message)
{
Init();
_instance.Caption = caption;
_instance.Message = message;
DialogResult result = _instance.ShowDialog();
return result;
}
private void MQButtonYes_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Yes;
this.Hide();
}
private void MQButtonNo_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.No;
this.Hide();
}
From the main form, its being called as:
MQMessageBox.Show("Warning", "Hello World");
this.Show(); //Adding this call, will show the main form again. Without this call, the mobile will show the Today Screen making it appear the app has crashed.
Main method is:
MQMainForm mainForm = new MQMainForm();
Application.Run(mainForm);
I know it is not what you want to hear, but calling the following code is not really valid:
private void MQButtonNo_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.No;
this.Hide();
}
The reason for this is that setting DialogResult is not the same as calling Form.Close(). I examined the implementation of Form in both the Compact Framework and the regular Framework in Reflector. Unfortunately I was not able to see the exact implementation of Form in the Compact Framework, but I was able to look into the regular implementation which should be similar.
The implementation of Close sets a flag that the Form is to be closed and then sends WM_CLOSE to the window. Setting DialogResult only sets a private variable in the Form. Now, I know what you are thinking, "but, I know that setting DialogResult closes the form! everyone knows that!". The key to understanding this behavior is how this happens. When you call Form.ShowDialog() it creates a new window message loop for the modal form. This creates a loop which processes window messages. The termination condition for this loop involves checking whether the user called Close() from the boolean that was set during close and/or whether DialogResult is set. Therefore, setting DialogResult will cause the message loop to terminate and close the Form.
From what I can tell, the problem with Hiding the Form is that you are setting DialogResult, but then when you hide the form, I believe that the Window is no longer receiving Window messages. Therefore, the message loop is probably waiting for the next message before checking the DialogResult's value.
You could experiment with this by getting a handle to the Form and sending it WM_CLOSE, but I'd imagine that going around the intended method of closing the Form to shave a few seconds of how long it takes, is probably not worth the cost of the probably unknown behavior of such a hack.
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