Closing multiple forms - winforms

I have three forms in my application.
Form1, Form2, and Form3.
Form1 opens Form2 and they are both open. This is OK. I want this to happen.
Form2 has a button that opens Form3. Again, this is desired behavior.
Form3 has two buttons... One that closes Form3 and goes back to Form1 and Form2 being open. I can do this one.
The problem is the second button on Form3... I need that button to close Form3 and Form2 so that only Form1 is now open.
Any ideas on how to close multiple forms at a time without closing the application?

Build a list of all Forms in the Application.OpenForms collection that are not of type Form1; then close them:
private void btnCloseAllExceptForm1_Click(object sender, EventArgs e)
{
List<Form> formsToClose = new List<Form>();
foreach(Form frm in Application.OpenForms)
{
if (!(frm is Form1))
{
formsToClose.Add(frm);
}
}
foreach(Form frm in formsToClose)
{
frm.Close();
}
}

Alternatively, you can have a local reference to the Form2 that opened the specific Form3 and pass it in Form3's constructor:
//references the Form2 that opens me (this is Form3)
private Form2 MyForm2Instance;
//you can add this in your existing Form3's constructor, or create a new one
public Form3(Form2 frm2)
{
InitializeComponent();
MyForm2Instance = frm2;
}
Then in your Form3's button you can have:
private void button1_Click(object sender, EventArgs e)
{
//this will close only the Form2 that opened this Form3
//and it will also close this Form3
MyForm2Instance.Close();
this.Close();
}
Now all you need is to change the way you open your Form3, by using the new constructor from Form2:
Form3 frm3 = new Form3(this);
frm3.Show();

Related

C# Closing Event on Child-Form if Closing Application

Good morning guys.
I have a little problem. If I close my Mainform (Windows-App) when my second form is opened, the second form closes without using my secondForm_FormClosing Event.
Anyone have a idea to handle this?
secondForm_FormClosing
The 2nd form is an Instance of a Form/Class itself so unless you have it setup as an MDI application the 2nd form won't receive the Closing or Closed event because the program is exiting.
You can tap into the 2nd Forms FormClosing event from Form1's closing event, this is one of many ways:
public Form1()
{
InitializeComponent();
frm2.FormClosing += new FormClosingEventHandler(form2_FormClosing);
frm2.Show();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
form2_FormClosing(null, e);
}
private void form2_FormClosing(object? sender, FormClosingEventArgs e)
{
// This will only get called "directly" when the second form is
// closed otherwise it will always be called from Form1_FormClosing.
}

(WPF) Does .Close() method releases the window instance?

I'm creating a new window in On_Click method. First I tried this;
public partial class MainWindow : Window
{
CustomerOperations customerOperationsWindow;
public MainWindow()
{
customerOperationsWindow = new CustomerOperations();
InitializeComponent();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
}
It's not working so I started creating the window instance every time the user clicks on the Customers button. And I used the following codes.
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
CustomerOperations customerOperationsWindow = new CustomerOperations();
customerOperationsWindow.Owner = this;
customerOperationsWindow.Show();
}
In the new window, If user clicks to Main button, I want to navigate to main window.
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Close();
this.Owner.Show();
}
First question: Does this.Close() releases the window instance?
Second question: Is this usage correct?
What do you think is the best practice?
Thank you all.
Window.Close() will dispose all resources allocated by the instance. That's why you cannot show it again once it was closed.
If you want to reuse the same Window instance, you should cancel the closing procedure to prevent disposal of internal resources and collapse the Window instead (by setting Window.Visibility to Visibility.Collapsed - Visibility.Collapsed is also the default value of an instantiated Window before Window.Show() is called).
Alternatively hide the Window by calling Window.Hide() (which will set the Visibility to Visibility.Hidden) instead of Window.Close().
Calling Window.Show will also set the window's visibility to Visibility.Visible.
As a matter of fact, showing a Window by setting Window.Visibility is the asynchronous version of Window.Show().
Generally, you switch between Window instances by using the Window.Activate method. Calling Window.Show on a Window that is currently showing/visible, does nothing.
public partial class MainWindow : Window
{
CustomerOperations CustomerOperationsWindow { get; }
public MainWindow()
{
InitializeComponent();
this.CustomerOperationsWindow = new CustomerOperations();
// Consider to move this logic to CustomerOperations class,
// where you can override the OnClosing method instead of subscribing to the event
this.CustomerOperationsWindow.Closing += CollapseWindow_OnClosing;
}
// Cancel close to prevent disposal and collapse Window instead
private void CollapseWindow_OnClosing(object sender, CancelEventArgs e)
{
e.Cancel = true;
this.CustomerOperationsWindow.Visibility = Visibility.Collapsed;
this.CustomerOperationsWindow.Owner.Activate();
}
private void btnCustomer_Click(object sender, RoutedEventArgs e)
{
this.CustomerOperationsWindow.Owner = this;
// Calling Show will set the Visibility to Visibility.Visible
this.CustomerOperationsWindow.Show();
}
}
Creating a Window instance allocates unmanaged resources. If this happens very frequently, you will keep the garbage collector busy. From a performance point of view you may want to avoid it and prefer to reuse the same instance.
In a common scenario this is not necessary. But since Window exposes a Hide() method, you may consider to use it instead of Close().
If you want to switch to the parent window, you can use the code this.Owner.Activate(); and if you want to close the current window, first this.Owner.Activate(); and then this.Close();.
When you enter this.Close(), the compiler does not execute the following lines after reaching it. And when a sample window still exists there is no need to recreate it
private void btnMain_Click(object sender, RoutedEventArgs e)
{
this.Owner.Activate();
this.Close();
}

Making a smooth transition between forms

I have 2 forms and want to alternate back and forth between them on button click in each. This can be done by opening the new form and closing the current one. However, from experience, if the new one takes time to fully show there can be a gap where no form is shown. I'm trying to use the Form.Shown event to avoid this:
private void button1_Click(object sender, EventArgs e)
{
var form2 = new Form2();
var shown = new AutoResetEvent(false);
form2.Shown += (ta, tb) => { shown.Set(); };
form2.Show();
shown.WaitOne();
Close();
}
However, it deadlocks on the WaitOne statement. It appears the Shown event isn't thrown until after the click method is finished. How else might I do it?

How to enable button on Main Window when secondary window is closing or get closed? - WPF VB.NET

I have two windows. Main Window & Window1.
On Main Window, there is a button1. When it is clicked, it gets disabled and open Window1. But i want to enable button1 on Main Window when Window1 is closing or get closed.
Create A Public Button in Window1
public Button mainBtn ;
on mainWindow in the button click event
private void button_click(object sender , RoutedEventArgs e){
Window1 win = new Window1();
this.button.IsEnabled = false;
win.mainBtn = this.button;
win.Show();
}
add on closing event to Window1
private void Window_closing(object sender , CancelEventArgs e){
mainBtn.IsEnabled = true;
}
the idea is to pass the MainWindow Button to the Window1 Button
then you can control it as like you want .
I guess you are using WinForms. In that case you have an event handler for the click on button1:
private void OnButton1Clicked(object sender, ...)
{
// show window 1
}
Now there are two methods to show a Form. You can show it as a modeless dialog box or as a modal dialog box.
Modal dialog boxes, which require the user to respond before continuing the program
Modeless dialog boxes, which stay on the screen and are available for use at any time but permit other user activities
Most dialog boxes you see are Modal: If you press file save, you'll have to finish the Save-File-Dialog box before you can continue editing.
The modal dialog box is the easiest
- Show them using using Form.ShowDialog.
- ShowDialog returns when the form is closed.
If you use a modal dialog box your code would look sequential:
private void OnButton1Clicked(object sender, ...)
{
using (Window1 window1 = new Window1())
{
// if needed window1.SetValues...
var dlgResult = window1.ShowDialog(this);
// if here, window 1 is closed
if (dlgResult = DialogResult.OK)
{ // ok button pressed
// if needed: window1 read resulting values
}
} // because of using window 1 automatically disposed
}
However if window1 is shown as a modeless dialog box, window1 will have to tell others that it is closed. Use event Form.Closed:
private Window1 window1 = null;
private void OnButton1Clicked(object sender, ...)
{
if (this.window1 != null) return; // window1 already shown
this.window1 = new Window1())
this.window1.Closing += this.OnFormClosed;
}
private void OnFormClosed(object sender, FormClosedEventArgs e)
{
Debug.WriteLine("window1 closed");
if (this.window1.DialogResult = DialogResult.OK)
{
// process dialog results
}
this.window1.Dispose();
this.window1 = null;
}
Data Binding is the strongest tool in WPF:
Add the button and bind the IsEnabled property to a public property in your view model or code behind. In the secondary window - when closing - update the property to reflect the new state.
Do not forget to implement INotifyPropertyChanged

If Form1 opens Form2 and registers for Form2.TextChanged, do I need to unregister Form2.TextChanged from within Form1 if Form2 is closing?

This is another question about well disposing objects from .NET. After having read a lot of different arcticles about dispose best practices (and people opinions), I was not able to get an answer for that one. I have 2 forms, Form1 and Form2.
Form1
void ShowFormButton_Click(object sender, eventargs e)
{
Form2 form = new Form2();
form.TextChanged += new eventhandler(form_TextChanged);
form.Show(this);
}
Form2
void CloseFormButton_Click(object sender, eventargs e)
{
Close();
}
When calling Close() in Form2, the Form2 should have is dispose() method call because it was opened by calling is Show() method but because Form1 has registered for the TextChanged event or Form2, will this keep Form2 from being disposed or make the process of disposing by the GC less efficient?
Thanks in advance
Form2 form = new Form2();
form.TextChanged += new eventhandler(form_TextChanged);
This means, that Form2 instance has reference to Form1 form_TextChanged method. When Form2 is closed, this doesn't prevent it to be collected, so in this case unsubscribing is not obligatory.
Let's say that Form2 subscribes to Form1 event. In this case, when Form2 is closed, Form1 still has active reference to Form2, and Form2 cannot be collected, creating memory leak.
So, the answer depends on subscription direction and event source/subscriber life time. In any case, if something is not clear, it is better to unregister events.

Resources