Basically I have two buttons on two forms, you click one of the buttons it hides the current form and displays the other form. The problem I have is that if a form is hidden, and I close the App with the “X” in the corner, the App still runs in the background. I’ve tried everything to get rid of it :’)
Code for Form1
:
namespace Reg_Login
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form1 form1 = new Form1();
Form2 form2 = new Form2();
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
string relativePath = Path.Combine(baseDirectory, "Users.txt");
StreamWriter writer = new StreamWriter(relativePath, append: true);
writer.WriteLine(txtCreateUser.Text + "t" + txtCreatePass.Text);
writer.Close();
if (txtCreateUser.Text == "" && txtCreatePass.Text == "")
{
MessageBox.Show("Please enter something");
}
else
{
MessageBox.Show("Account Created");
this.Hide();
form2.Show();
}
}
private void button2_Click(object sender, EventArgs e)
{
Form1 form1 = new Form1();
Form2 form2 = new Form2();
this.Hide();
form2.Show();
form2.BringToFront();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
System.Windows.Forms.Application.Exit();
}
}
}
Code for Form2
:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Reg_Login
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
string relativePath = Path.Combine(baseDirectory, "Users.txt");
StreamReader reader = new StreamReader(relativePath);
string lineRec = reader.ReadLine();
string[] lineArray = new string[2];
string userName = "";
string Password = "";
while (lineRec != null)
{
lineArray = lineRec.Split("t");
userName = lineArray[0];
Password = lineArray[1];
if (txtUser.Text == userName && txtPass.Text == Password)
{
MessageBox.Show("WORKS");
break;
}
lineRec = reader.ReadLine();
}
if (txtUser.Text != userName && txtPass.Text != Password)
{
MessageBox.Show("DOES NOT WORK");
}
reader.Close();
}
private void button2_Click(object sender, EventArgs e)
{
Form1 form1 = new Form1();
Form2 form2 = new Form2();
this.Hide();
form1.Show();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
System.Windows.Forms.Application.Exit();
}
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
System.Windows.Forms.Application.Exit();
}
Should work but it’s not.
3
To make your app close properly, follow this general advice.
- Make all child forms members of the MainForm class (in this case the main window is Form 1)
- Whenever you
Show()
a child form, pass thethis
pointer of the parent window. This way the child window will always be on top and you won’t have to “BringToFront”. - Make sure to override the FormClosing event in any child form. If user is closing it, cancel the
Close
andHide
it instead. This way the native window handle doesn’t get disposed before you want it to.
Another change is that I added a handler that tracks the visibility of form 2 and makes form 1 visibility “the opposite of that”.
Some functionality has been shortened for clarity, but the aim here is to show the proper management of window Handle
so that your app closes properly.
Form 1 (Main Window)
public partial class Form1 : Form
{
internal static string UserPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Users.txt");
/// <summary>
/// The main window of the app.
/// </summary>
public Form1()
{
InitializeComponent();
txtCreatePass.PasswordChar = '*';
#if false
// A way to reset the file for debugging.
if(File.Exists(UserPath)) File.Delete(UserPath);
#endif
form2.VisibleChanged += (sender, e) =>
{
// Hide this for when form2 shows.
if (form2.Visible) Hide();
else
{
if (form2.DialogResult == DialogResult.Yes)
{
// Exit the app if form 2 has requested it.
Close();
}
else
{
// Show this for when form2 hides.
Show();
}
}
};
}
// This should be a class member.
Form2 form2 = new Form2();
private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtCreateUser.Text) || string.IsNullOrWhiteSpace(txtCreatePass.Text))
{
// SKIP THIS CHECK by simply making [Button 1] invisible until the form is valid.
MessageBox.Show("Please fill out form completely");
}
else
{
MessageBox.Show("Account Created");
// Shortened for clarity
// MAKE SURE YOU NEVER 'REALLY' SAVE A PASSWORD IN THIS MANNER. REALLY. NEVER.
File.AppendAllLines(UserPath, [$"{txtCreateUser.Text}t{txtCreatePass.Text}"]);
// Add 'this'
form2.Show(this);
}
}
private void button2_Click(object sender, EventArgs e)
{
Hide();
// Add 'this'
form2.Show(this);
// No need to do this form2.BringToFront();
}
// Don't do this
//private void Form1_FormClosed(object sender, FormClosedEventArgs e)
//{
// System.Windows.Forms.Application.Exit();
//}
}
Form 2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
txtPass.PasswordChar = '*';
}
private void button1_Click(object sender, EventArgs e)
{
// Shortened for clarity
if(File.Exists(Form1.UserPath))
{
foreach (var line in File.ReadAllLines(Form1.UserPath))
{
var lineArray = line.Split("t");
if (txtUser.Text == lineArray[0] && txtPass.Text == lineArray[1])
{
MessageBox.Show("WORKS");
return;
}
}
MessageBox.Show("DOES NOT WORK - did you ever assign txtName.Text and txtPass.Text?");
return;
}
MessageBox.Show("FILE DOES NOT EXIST");
}
private void button2_Click(object sender, EventArgs e)
{
Hide();
}
// DO Add this to prevent this window from disposing when user clicks [X]
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (!Modal && e.CloseReason == CloseReason.UserClosing)
{
DialogResult = MessageBox.Show(
this,
"Exit app?",
"Form 2 wants to close app",
buttons: MessageBoxButtons.YesNo);
e.Cancel = true;
Hide();
}
base.OnFormClosing(e);
}
// Don't do this
//private void Form2_FormClosed(object sender, FormClosedEventArgs e)
//{
// System.Windows.Forms.Application.Exit();
//}
}
Another thing you can put in the Form 1 constructor, that shouldn’t be necessary but might provide some cheap insurance, is an explicit dispose when the main form does.
// Shouldn't be necessary, but it's cheap insurance.
public Form1()
{
Disposed += (sender, e) =>
{
form2.Dispose();
};
}
As mentioned, everytime you want to show a form, you create object representing it with new
keyword. So you have many abandoned objects that may hold resources and keep your app alive.
You are showing just 2 forms and you just need one object for each form to display and hide them. The trick is that each form has to hold reference to the other form to manage it. Here’s my skeleton code which works as expected:
// Form1.cs
public partial class Form1 : Form
{
private readonly Form2 _form2;
public Form1()
{
InitializeComponent();
FormClosing += (s, e) => Application.Exit();
_form2 = new Form2(this);
}
private void button1_Click(object sender, EventArgs e)
{
Hide();
_form2.Show();
}
}
// Form2.cs
public partial class Form2 : Form
{
private readonly Form1 _form1;
public Form2(Form1 form1)
{
InitializeComponent();
FormClosing += (s, e) => Application.Exit();
_form1 = form1;
}
private void button1_Click(object sender, EventArgs e)
{
Hide();
_form1.Show();
}
}