首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

C# WinForm 登錄窗口關閉並打開主窗口的正確實現模式

     編輯:Java 相關知識

WinForm 登錄到主窗口跳轉的標準實現方案

在 C# WinForm 應用中,實現「登錄成功關閉登錄窗、打開主窗口」看似簡單,實則涉及程序生命周期、線程模型、窗口所有權鏈等核心機制。本文分析常見錯誤模式,提供三種標準實現方案。

一、錯誤模式分析

1.1 直接 Show + Close 導致程序退出


// ❌ 錯誤代碼:Program.cs
static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FormLogin()); // 以登錄窗為主窗口啟動
    }
}

// FormLogin.cs 登錄成功處理
private void btnLogin_Click(object sender, EventArgs e) {
    if (ValidateUser(txtUser.Text, txtPwd.Text)) {
        FormMain main = new FormMain();
        main.Show();      // 顯示主窗口
        this.Close();     // 關閉登錄窗口 → 程序退出!
    }
}

原因:Application.Run(form) 以參數窗口為「主窗口」,當主窗口關閉時,消息循環結束,程序退出。this.Close() 關閉主窗口導致應用終止,新創建的 FormMain 隨之銷毀。

二、標準方案一:DialogResult 模式(最推薦)

2.1 程序入口調整


// Program.cs
static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        
        // 1. 創建並顯示登錄對話框
        using (FormLogin loginForm = new FormLogin()) {
            // ShowDialog 為模態對話框,阻塞直到關閉
            DialogResult result = loginForm.ShowDialog();
            
            // 2. 根據返回值決定是否啟動主程序
            if (result == DialogResult.OK) {
                Application.Run(new FormMain()); // 以主窗口啟動消息循環
            }
            // Else: 用戶取消/關閉,程序自然結束
        }
    }
}

2.2 登錄窗口實現


// FormLogin.cs
public partial class FormLogin : Form {
    public FormLogin() {
        InitializeComponent();
    }
    
    private void btnLogin_Click(object sender, EventArgs e) {
        string user = txtUser.Text.Trim();
        string pwd = txtPwd.Text;
        
        if (Authenticate(user, pwd)) {
            // 關鍵:設置 DialogResult 為 OK
            this.DialogResult = DialogResult.OK;
            // 這裡不需要手動 Close(),設置 DialogResult 會自動關閉模態對話框
        } else {
            MessageBox.Show("用戶名或密碼錯誤", "登錄失敗", 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
            txtPwd.Clear();
            txtPwd.Focus();
        }
    }
    
    private bool Authenticate(string user, string pwd) {
        // 實際項目調用服務層驗證
        return "admin".Equals(user) && "123456".Equals(pwd);
    }
    
    // 可選:取消按鈕
    private void btnCancel_Click(object sender, EventArgs e) {
        this.DialogResult = DialogResult.Cancel;
    }
}

2.3 原理優勢

  • 生命周期清晰:登錄窗為模態對話框,主窗口為應用主窗口
  • 無殘留引用:using 確保登錄窗資源釋放
  • 符合 WinForm 設計:Application.Run 僅調用一次,對應唯一主窗口
  • 易擴展:可輕鬆添加「記住密碼」、「自動登錄」等邏輯

三、標準方案二:隱藏主窗口模式

適用於「啟動即顯示主窗口,未登錄時遮罩/禁用」的場景:

3.1 實現邏輯


// Program.cs
static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        
        FormMain mainForm = new FormMain();
        // 主窗口構造器中處理登錄邏輯
        Application.Run(mainForm);
    }
}

// FormMain.cs
public partial class FormMain : Form {
    public FormMain() {
        InitializeComponent();
        
        // 1. 初始化時隱藏主界面
        this.Hide(); // 或設置 Opacity=0、禁用控件
        
        // 2. 顯示登錄對話框
        using (FormLogin login = new FormLogin()) {
            if (login.ShowDialog(this) != DialogResult.OK) {
                // 登錄失敗/取消 → 退出程序
                Environment.Exit(0);
                return;
            }
        }
        
        // 3. 登錄成功 → 顯示主界面
        this.Show();
        this.WindowState = FormWindowState.Maximized;
    }
}

四、標準方案三:ApplicationContext 自定義上下文(高級)

完全控制應用生命周期,支持多窗口切換、托盤運行等複雜場景:

4.1 自定義 ApplicationContext


// AppContext.cs
public class AppContext : ApplicationContext {
    private FormLogin loginForm;
    private FormMain mainForm;
    
    public AppContext() {
        ShowLogin();
    }
    
    private void ShowLogin() {
        loginForm = new FormLogin();
        loginForm.LoginSuccess += OnLoginSuccess;
        loginForm.FormClosed += (s, e) => {
            if (mainForm == null) ExitThread(); // 登錄窗關閉且無主窗口 → 退出
        };
        loginForm.Show();
    }
    
    private void OnLoginSuccess(object sender, EventArgs e) {
        loginForm.LoginSuccess -= OnLoginSuccess;
        loginForm.Hide(); // 隱藏而非關閉,保持實例
        
        mainForm = new FormMain();
        mainForm.FormClosed += (s, e) => {
            // 主窗口關閉 → 可選:重新登錄 或 退出
            // ShowLogin(); // 重新登錄
            ExitThread();  // 退出程序
        };
        mainForm.Show();
    }
}

// Program.cs
static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new AppContext());
    }
}

五、進階場景:記住我/自動登錄


// FormLogin.cs 擴展
private void FormLogin_Load(object sender, EventArgs e) {
    // 讀取記住的用戶名
    string savedUser = Properties.Settings.Default.RememberedUser;
    if (!string.IsNullOrEmpty(savedUser)) {
        txtUser.Text = savedUser;
        chkRemember.Checked = true;
    }
    
    // 自動登錄邏輯
    if (Properties.Settings.Default.AutoLogin && !string.IsNullOrEmpty(savedUser)) {
        string savedPwd = Properties.Settings.Default.SavedPassword; // 實際應加密存儲
        if (Authenticate(savedUser, savedPwd)) {
            // 延遲執行避免界面閃爍
            this.BeginInvoke(new Action(() => {
                this.DialogResult = DialogResult.OK;
            }));
        }
    }
}

private void btnLogin_Click(object sender, EventArgs e) {
    if (Authenticate(txtUser.Text, txtPwd.Text)) {
        // 保存設置
        if (chkRemember.Checked) {
            Properties.Settings.Default.RememberedUser = txtUser.Text;
            // 實際項目:加密存儲密碼或 Token
        } else {
            Properties.Settings.Default.RememberedUser = "";
        }
        Properties.Settings.Default.AutoLogin = chkAutoLogin.Checked;
        Properties.Settings.Default.Save();
        
        this.DialogResult = DialogResult.OK;
    }
}

六、核心知識點總結

概念說明
Application.Run(Form)啟動消息循環,參數 Form 為主窗口,關閉則退出
Form.Show()非模態顯示,不阻塞調用線程
Form.ShowDialog()模態顯示,阻塞直到關閉,返回 DialogResult
DialogResult 屬性設置後自動關閉模態對話框,作為 ShowDialog 返回值
主窗口關閉行為可通過 FormClosing 事件攔截(如最小化到托盤)

掌握 WinForm 應用程序模型與窗口生命周期,是構建穩健桌面應用的基石。推薦方案一作為默認選擇,方案三應對複雜架構需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved