如何使用Await方法加载新页面

时间:2018-11-03 08:41:42

标签: c# wpf forms async-await

这是我的登录方法:

    #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方法,但它仍然会延迟打开。

3 个答案:

答案 0 :(得分:1)

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

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

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

您应该执行以下操作:

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

如果您显示更多代码,我会更加精确。

答案 1 :(得分:1)

看看这一行this.Dispatcher.Invoke(() =>

Dispatcher.Invoke是一个同步调用,它将阻止您的线程运行直到完成。在回调返回之前,控件将不会返回到调用对象,因此会导致GUI不响应。

您可能想使用Dispatcher.BeginInvoke而不是Dispatcher.Invokeexample),它是异步操作。或仅在确实需要修改或更新UI内容时才使用Dispatcher.Invoke 。例子

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

答案 2 :(得分: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();
    }

希望这能回答您的问题