C# Windows 窗体自动关闭

问题描述 投票:0回答:3

我有一个 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窗体没有关闭。

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

c# winforms dispose
3个回答
2
投票

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

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

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


0
投票

编辑:问题原因

无需过多挖掘杂草,应用程序的生命周期就与 WinForms 中的主窗口相关联。有些东西可以延长生命周期,例如分离线程,但我不会详细讨论这一点。

在此处的代码中,对

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

还有另一个问题,即使您没有调用

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

解决方案

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

一个相对简单的方法(使用 WinForms)是使用一个空表单作为应用程序的主页,有一个名为

IsMdiContainer
的属性,如果您设置为
true
,将允许该表单包含其他表单。

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

您不必使用表单或“多文档界面”功能,但我喜欢使用

OnLoad
OnFormClosing
功能。如果您不需要这些,您可以只在页面中使用 UserControl,并将
IsMdiParent
设置为其默认值
false


0
投票

您的帖子指出您的目标是首先显示登录表单,需要用户凭据在显示主表单之前。实现此目的的一种方法是强制创建主窗口句柄,同时通过覆盖

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 = "********";
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.