我有一个 Windows 应用程序,其中我的第一个 Windows 表单是登录。 成功登录后,必须打开“主页”表单。 我在调试时看到“Home”表单,但是一旦代码进入 Home.Designer.cs 中的 Dispose 方法,我的应用程序就会停止。
我的登录页面代码如下所示:
private void loginbtn_Click(object sender, EventArgs e)
{
String username = "admin";
String password = "admin";
String @uname = Unametxtbox.Text;
String @pass = Passtextbox.Text;
if (@uname.Equals(username) && @pass.Equals(password))
{
MessageBox.Show("Login Successful");
Home home = new Home();
home.Show();
this.Close();
}
else
{
MessageBox.Show("Invalid Credentials!");
}
}
我的 Home.cs 页面如下所示:
public partial class Home : Form
{
public Home()
{
InitializeComponent();
}
}
Home.Designer.cs 有以下代码:
partial class Home
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Home));
this.label1 = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.closebtn = new System.Windows.Forms.PictureBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.Storedbtn = new System.Windows.Forms.Button();
this.Soldbtn = new System.Windows.Forms.Button();
this.Transbtn = new System.Windows.Forms.Button();
this.Supbtn = new System.Windows.Forms.Button();
this.Empbtn = new System.Windows.Forms.Button();
this.Custbtn = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.closebtn)).BeginInit();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.PictureBox closebtn;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button Storedbtn;
private System.Windows.Forms.Button Soldbtn;
private System.Windows.Forms.Button Transbtn;
private System.Windows.Forms.Button Supbtn;
private System.Windows.Forms.Button Empbtn;
private System.Windows.Forms.Button Custbtn;
}
如果我评论 this.Close();在loginbtn_Click中,我可以看到Windows窗体,但是登录Windows窗体没有关闭。
我在这里缺少什么,提前谢谢。
无需过多挖掘杂草,应用程序的生命周期就与 WinForms 中的主窗口相关联。有些东西可以延长生命周期,例如分离线程,但我不会详细讨论这一点。
在此处的代码中,对
this.Close()
的调用有效地终止了应用程序,因为就 Windows 事件循环而言,一旦主窗口消失,您就完成了应用程序。
还有另一个问题,即使您没有调用
this.Close()
,您也会创建一个 Home 对象,该对象位于函数内的局部变量内。一旦到达 if
语句的末尾,对该对象的最后一个引用就消失了。当垃圾收集器调用时,它将无法到达您的 Home 对象,这会触发它被销毁和释放。该对象需要存储在函数调用完成后将持续存在的地方。
我使用 WinForms 已经有一段时间了,据我所知,没有真正的方法来处理这样的“页面”。还有其他框架(例如 WPF)在这方面做得更好。如果我对 WinForms 处理不当的看法是错误的,也许有人会纠正我。
一个相对简单的方法(使用 WinForms)是使用一个空表单作为应用程序的主页,有一个名为
IsMdiContainer
的属性,如果您设置为 true
,将允许该表单包含其他表单。
在此主窗口窗体中,我将添加一个函数来加载接受要加载的页面的新页面。它关闭当前页面并打开新页面。根据您需要在页面之间传递哪些信息,可以采用多种不同的方法来执行此操作。传递信息的粗略但简单的方法是仅将最重要的信息保留在主窗口中,然后孩子们可以访问它,但它确实将您的课程更多地结合在一起。
您不必使用表单或“多文档界面”功能,但我喜欢使用
OnLoad
和 OnFormClosing
功能。如果您不需要这些,您可以只在页面中使用 UserControl,并将 IsMdiParent
设置为其默认值 false
。
您的帖子指出您的目标是首先显示登录表单,需要用户凭据在显示主表单之前。实现此目的的一种方法是强制创建主窗口句柄,同时通过覆盖
SetVisibleCore
来防止其变得可见,直到用户成功登录。如果登录被取消(或者用户验证失败),则退出应用程序)。通过有效登录,应用程序将继续使用 HomeForm 作为主应用程序窗口。
public partial class HomeForm : Form
{
public HomeForm()
{
InitializeComponent();
// Ordinarily we don't get the handle until
// window is shown. But we want it now.
_ = Handle;
// Call BeginInvoke on the new handle so as not to block the CTor.
BeginInvoke(new Action(()=> execLoginFlow()));
// Ensure final disposal of login form. Failure to properly dispose of window
// handles is the leading cause of the kind of exit hang you describe.
Disposed += (sender, e) => _loginForm.Dispose();
buttonSignOut.Click += (sender, e) => IsLoggedIn = false;
}
private LoginForm _loginForm = new LoginForm();
protected override void SetVisibleCore(bool value) =>
base.SetVisibleCore(value && IsLoggedIn);
bool _isLoggedIn = false;
public bool IsLoggedIn
{
get => _isLoggedIn;
set
{
if (!Equals(_isLoggedIn, value))
{
_isLoggedIn = value;
onIsLoggedInChanged();
}
}
}
private void onIsLoggedInChanged()
{
if (IsLoggedIn)
{
WindowState = FormWindowState.Maximized;
Text = $"Welcome {_loginForm.UserName}";
Visible = true;
}
else execLoginFlow();
}
private void execLoginFlow()
{
Visible = false;
while (!IsLoggedIn)
{
_loginForm.StartPosition = FormStartPosition.CenterScreen;
if (DialogResult.Cancel == _loginForm.ShowDialog(this))
{
switch (MessageBox.Show(
this,
"Invalid Credentials",
"Error",
buttons: MessageBoxButtons.RetryCancel))
{
case DialogResult.Cancel: Application.Exit(); return;
case DialogResult.Retry: break;
}
}
else
{
IsLoggedIn = true;
}
}
}
}
登录表格
public partial class LoginForm : Form
{
public LoginForm()
{
InitializeComponent();
StartPosition = FormStartPosition.Manual;
FormBorderStyle = FormBorderStyle.FixedToolWindow;
textBoxUid.Text = "Admin";
textBoxUid.TextChanged += onOnyTextChanged;
textBoxPswd.TextChanged += onOnyTextChanged;
buttonLogin.Enabled = false;
buttonLogin.Click += (sender, e) => DialogResult = DialogResult.OK;
}
private void onOnyTextChanged(object sender, EventArgs e)
{
buttonLogin.Enabled = !(
(textBoxUid.Text.Length == 0) ||
(textBoxPswd.Text.Length == 0)
);
}
public string UserName => textBoxUid.Text;
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
textBoxPswd.Clear();
textBoxPswd.PlaceholderText = "********";
}
}
}