【问题标题】:How to load new page with Await method如何使用 Await 方法加载新页面
【发布时间】:2019-04-07 08:33:25
【问题描述】:

这是我的登录方法:

    #region LoginMethod
    bool login = false;
    public async Task GetAccounts()
    {
        MainWin w = new MainWin();

        await Task.Run(() =>
        {
            this.Dispatcher.Invoke(() =>
            {
                using (SqlConnection connection = new SqlConnection(PublicVar.ConnectionString))
                {
                    gymEntities2 database = new gymEntities2();
                    SqlConnection con1 = new SqlConnection(PublicVar.ConnectionString);
                    PublicVar.TodayTime = String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(TimeNow.Text));
                    con1.Open();

                    SqlCommand Actives = new SqlCommand("Select DISTINCT (LockEndDate) from LockTable Where Username = '" + txt_username.Text + "' and Password = '" + txt_password.Password + "'", con1);
                    object Active = Actives.ExecuteScalar();
                    string SystemActive = Convert.ToString(Active);

                    //   SqlCommand Commandcmds = new SqlCommand("update VW_TimeOut set UserActive = 2 where UserEndDate < '" + String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(TimeNow.Text)) + "'", con1);
                    //   Commandcmds.ExecuteScalar();

                    SqlCommand Commandcmd = new SqlCommand("SELECT COUNT(*) FROM LockTable Where Username = '" + txt_username.Text + "' and Password = '" + txt_password.Password + "' and LockEndDate between '" + String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(Lock.Text)) + "' And '" + SystemActive + "'", con1);
                    int userCount = (int)Commandcmd.ExecuteScalar();

                    //Find Gym ID -> To Set Public Value Strings
                    SqlCommand FindGymID = new SqlCommand("Select DISTINCT (LockID) from LockTable Where Username = '" + txt_username.Text + "' and Password = '" + txt_password.Password + "'", con1);
                    object ObGymID = FindGymID.ExecuteScalar();

                    if (userCount > 0)
                    {
                        try
                        {
                            RegistryKey UsernameKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\GYM");

                            if (CheakRem.IsChecked == true)
                                if ((string)UsernameKey.GetValue("UserNameRegister") != "")
                                {
                                    UsernameKey.SetValue("UserNameRegister", txt_username.Text.Trim());
                                    UsernameKey.SetValue("PasswordRegister", Module.Decode.EncryptTextUsingUTF8(txt_password.Password.Trim()));
                                }

                            PublicVar.GymID = Convert.ToString(ObGymID);
                            login = true;
                        }
                        catch
                        {

                            w.Username = null;
                            w.Password = null;
                        }
                    }
                    else
                    {
                        ErrorPage pageerror = new ErrorPage();

                        con1.Close();
                        w.Username = null;
                        w.Password = null;
                    }
                    con1.Close();
                }
            });
        });

        if (login == true)
        {
            w.Username = txt_username.Text;
            w.Password = txt_password.Password;
            w.Show();
            this.Close();
        }
    }
    #endregion

但它不起作用 - 每当我按下按钮时,我的表单都会挂起。

private async void btn_join_Click(object sender, RoutedEventArgs e)
{
    await GetAccounts();
}

当我按下异步按钮时,它不起作用,我的程序被挂起。 我的方法的哪一部分是错误的? 我真正想要的是打开一个新页面的按钮, 但我不希望它延迟打开...有人告诉我使用 await 方法,但它仍然延迟打开。

【问题讨论】:

    标签: c# wpf forms async-await


    【解决方案1】:

    以上两个答案都是正确的。但也许修复你的代码会让事情变得更清楚。您应该按照上面的建议和如下所示将 UI 与任务分开。希望我没有语法错误,因为我只是在没有 IDE 的情况下对其进行了修改。基本上,我将 GetAccounts 更改为仅处理数据库并让 PopulateMethodAsync 处理 UI。这意味着 GetAccounts 将在后台运行,完成后会将结果提供给 UI 部分 (PopulateMethodAsync)。

        #region LoginMethod
        bool login = false;
        public async Task PopulateMethodAsync()
        {
            var isLoginSuccess = await GetAccounts(txt_username.Text.Trim(), txt_password.password.Text.Trim(), Lock.Text.Trim(), TimeNow.Text.Trim());
    
            MainWin w = new MainWin();
    
            if (login == true)
            {
                w.Username = txt_username.Text;
                w.Password = txt_password.Password;
                w.Show();
                this.Close();
            }
            else
            {
                w.Username = null;
                w.Password = null;
            }
        }
    
        public async Task<bool> GetAccounts(string txt_username, string txt_password, string Lock, string TimeNow)
        {
            await Task.Run(() =>
            {
                using (SqlConnection connection = new SqlConnection(PublicVar.ConnectionString))
                {
                    gymEntities2 database = new gymEntities2();
                    SqlConnection con1 = new SqlConnection(PublicVar.ConnectionString);
                    PublicVar.TodayTime = String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(TimeNow));
                    con1.Open();
    
                    SqlCommand Actives = new SqlCommand("Select DISTINCT (LockEndDate) from LockTable Where Username = '" + txt_username + "' and Password = '" + txt_password + "'", con1);
                    object Active = Actives.ExecuteScalar();
                    string SystemActive = Convert.ToString(Active);
    
                    //   SqlCommand Commandcmds = new SqlCommand("update VW_TimeOut set UserActive = 2 where UserEndDate < '" + String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(TimeNow.Text)) + "'", con1);
                    //   Commandcmds.ExecuteScalar();
    
                    SqlCommand Commandcmd = new SqlCommand("SELECT COUNT(*) FROM LockTable Where Username = '" + txt_username + "' and Password = '" + txt_password + "' and LockEndDate between '" + String.Format("{0:yyyy/MM/dd}", Convert.ToDateTime(Lock)) + "' And '" + SystemActive + "'", con1);
                    int userCount = (int)Commandcmd.ExecuteScalar();
    
                    //Find Gym ID -> To Set Public Value Strings
                    SqlCommand FindGymID = new SqlCommand("Select DISTINCT (LockID) from LockTable Where Username = '" + txt_username + "' and Password = '" + txt_password + "'", con1);
                    object ObGymID = FindGymID.ExecuteScalar();
    
                    if (userCount > 0)
                    {
                        try
                        {
                            RegistryKey UsernameKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\GYM");
    
                            if (CheakRem.IsChecked == true)
                                if ((string)UsernameKey.GetValue("UserNameRegister") != "")
                                {
                                    UsernameKey.SetValue("UserNameRegister", txt_username);
                                    UsernameKey.SetValue("PasswordRegister", Module.Decode.EncryptTextUsingUTF8(txt_password));
                                }
    
                            PublicVar.GymID = Convert.ToString(ObGymID);
    
                            con1.Close();
    
                            return true;
                        }
                        catch
                        {
    
                        }
                    }
    
                    con1.Close();
                }
            });
    
            return false;
        }
        #endregion
    
        private async void btn_join_Click(object sender, RoutedEventArgs e)
        {
            await PopulateMethodAsync();
        }
    

    希望这能回答你的问题

    【讨论】:

      【解决方案2】:

      您在任务方法中使用 Dispatcher.Invoke() 挂起程序。

      Dispatcher.Invoke() 使代码在 WPF 的 UI 线程上同步执行,并且在此代码完成之前不会返回。同时,在您的“异步按钮”中,代码​​等待任务完成,这就是您的死锁。

      您不需要 Task.Run 与 Dispatcher.Invoke。

      你应该这样做:

      1. 创建并显示您的表单。
      2. await Task.Run - 从数据库中获取数据,但不要在 UI 中推送任何内容。您可以将值返回到一个简单的类中 并用于创建类型化任务。
      3. 使用从数据库返回的值填充 UI。

      如果你显示更多代码,我可以更精确。

      【讨论】:

      • 当我清理 Invoke 时出现此错误调用线程无法访问此对象,因为当我按下按钮时另一个线程拥有它。
      • 您需要查看我的代码的哪一部分?因为这是我用于登录的所有方法,然后我在异步按钮上使用它
      • 如果可以的话,制作该类并重新发布类方法并编辑此代码。
      • 确保您不要从您的 Task.Run 代码访问表单控件。相反,创建一个具有两个属性的类:用户名和密码。从 Task 中返回此类的新实例以及您需要的结果。然后,等待此任务后,填充表单控件并在屏幕上显示表单。
      • 我是新人,你能做那个类并改变我的主要方法吗?
      【解决方案3】:

      看看这行this.Dispatcher.Invoke(() =&gt;

      Dispatcher.Invoke 是一个同步调用,它会阻止你的线程运行直到它完成。直到回调返回后,控件才会返回到调用对象,因此导致 GUI 无响应。

      您可能希望使用异步操作Dispatcher.BeginInvoke 而不是Dispatcher.Invoke (example)。或使用Dispatcher.Invoke仅当您确实需要修改或更新 UI 内容。例如,

      Dispatcher.Invoke(() =>
      {
          w.Username = null;
          w.Password = null;
      });
      

      【讨论】:

      • 我收到此错误:将 lambda 表达式转换为类型“Delegate”,因为它不是委托类型 MYProject1
      猜你喜欢
      • 2013-09-09
      • 2019-11-13
      • 2011-10-31
      • 2020-06-27
      • 2013-09-17
      • 2020-01-04
      • 2011-04-12
      • 2015-01-10
      • 2018-03-30
      相关资源
      最近更新 更多