繁体   English   中英

C# Windows 窗体自动关闭

[英]C# Windows form closing automatically

我有一个 Windows 应用程序,我的第一个 Windows 窗体是登录。 成功登录后,它必须打开“主页”表单。 我在调试时看到“主页”表单,但是一旦代码进入 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 窗体,但没有关闭 Login Windows 窗体。

我在这里缺少什么,提前致谢。

尝试使用隐藏而不是关闭。

Hide();
Home home = new Home();
home.ShowDialog();
Close();

欲了解更多信息,您可以访问微软官方网站

编辑:问题原因

无需深入挖掘,应用程序的生命周期与 WinForms 中的主窗口相关联。 有些东西可以延长生命周期,例如分离线程,但我不会深入探讨。

在此处的代码中,对this.Close()的调用有效地终止了应用程序,因为就 Windows 事件循环而言,一旦主窗口消失,您就完成了应用程序。

但是还有另一个问题,即使您没有调用this.Close() ,您也正在创建一个 Home 对象,它位于函数的局部变量中。 一旦到达if语句的末尾,您对该对象的最后引用就消失了。 当垃圾收集器调用时,它将无法访问您的 Home 对象,这会触发它被销毁和释放。 该对象需要存储在函数调用完成后将持续存在的某个位置。

解决方案

我使用 WinForms 已经有一段时间了,据我所知,没有真正的方法来处理这样的“页面”。 还有其他框架(例如 WPF)在这方面做得更好。 如果我对 WinForms 处理不当的看法是错误的,也许有人会纠正我。

一种相对简单的方法(使用 WinForms)是使用一个空表单作为应用程序的主页,有一个名为IsMdiContainer的属性,如果您将其设置为true ,将允许此表单包含其他表单。

在这个主窗口窗体中,我将添加一个函数来加载一个新页面,该页面接受要加载的页面。 它关闭当前页面并打开新页面。 根据您需要在页面之间传递的信息,有多种不同的方法可以做到这一点。 传递信息的粗略但简单的方法是仅将最重要的信息保留在主窗口中,然后孩子们可以访问它,但它确实将您的课程更多地结合在一起。

您不必使用表单或“多文档界面”功能,但我喜欢使用OnLoadOnFormClosing函数。 如果您不需要这些,您可以只为您的页面使用 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 = "********";
        }
    }
}

登录流程

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM