You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么使用多线程实现登录时,Label的MouseDown事件需要点击两次才生效?

根本原因

你的代码逻辑执行顺序存在错误:

  • 调用user_login_thread.Start()后,登录线程刚启动尚未执行完User_Login逻辑,你就立刻判断if (login.UserLoggedIn),此时这个标识还是默认值false,第一次点击时跳转逻辑根本不会执行
  • 后续你调用user_login_thread.Join()阻塞了UI线程,等登录线程执行完成、UserLoggedIn被改为true时,前面的跳转判断代码已经执行完毕,不会再触发
  • 第二次点击时,上一次登录操作已经把UserLoggedIn设为true,启动线程后立刻判断就能命中条件完成跳转,这就是需要点击两次的核心原因

其他隐藏问题

  • 你在非UI线程的User_Login中调用MessageBox.Show,属于跨线程操作UI,会出现不可预期的异常或行为
  • 开启多线程后调用Join会直接卡住UI线程,完全失去了多线程避免界面卡顿的意义
  • 不要使用全局数据库连接conn,多线程环境下极易出现连接状态异常,最好每次操作数据库时新建连接、用完自动释放

修复方案

把跳转、记住密码的逻辑都移到登录完成之后执行,所有UI操作都要切回UI线程运行,参考修改代码如下:

private async void tbLogin_MouseDown(object sender, MouseButtonEventArgs e)
{
    // 先赋值登录参数
    login.Student_Email = txtstd_Email.Text;
    login.Student_Password = txtstd_Password.Password;

    // 用Task开后台线程执行登录,不会阻塞UI
    bool loginSuccess = await Task.Run(() => User_Login(login.Student_Email, login.Student_Password));

    if (loginSuccess)
    {
        // 登录成功后再执行跳转,await会自动切回UI线程,可以直接操作UI
        foreach (Window window in Application.Current.Windows)
        {
            if (window is MainWindow mainWindow)
            {
                mainWindow.frmView.Source = new Uri("Views/Dashboard.xaml", UriKind.Relative);
            }
        }

        if (chkRemember.IsChecked == true)
        {
            Properties.Settings.Default.Student_Email = login.Student_Email;
            Properties.Settings.Default.Student_Password = login.Student_Password;
            Properties.Settings.Default.Save();
        }
    }
}

// 修改User_Login返回登录结果,不要在内部直接操作UI
private bool User_Login(string email, string password)
{
    Secure security = new Secure();
    // 每次操作新建数据库连接,用using自动释放
    using (SqlConnection conn = new SqlConnection("你的数据库连接字符串"))
    {
        conn.Open();
        string sql = "SELECT Student_Password FROM Student_Data WHERE Student_Email=@Email";
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            cmd.Parameters.Add("@Email", System.Data.SqlDbType.VarChar, 55).Value = email;
            SqlDataReader reader = cmd.ExecuteReader();
            if (reader.Read() && login.Student_Password.Equals(security.Decrypt(reader["Student_Password"].ToString())))
            {
                login.UserLoggedIn = true;
                return true;
            }
            else
            {
                // 切回UI线程弹出错误提示
                Application.Current.Dispatcher.Invoke(() =>
                {
                    MessageBox.Show("Login Unsuccessful", "Student Login Unsuccessfull", MessageBoxButton.OK, MessageBoxImage.Error);
                });
                return false;
            }
        }
    }
}

如果课程要求必须使用Thread而不能用Task,只需要在Thread的执行逻辑末尾,通过Dispatcher把登录成功后的后续操作抛到UI线程执行即可,不要在启动线程后立刻判断登录状态。

内容的提问来源于stack exchange,提问作者PureWare -Legends Of Gaming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:15:02