Как загрузить новую страницу методом Await - PullRequest
0 голосов
/ 03 ноября 2018

Вот что у меня есть для моего метода входа:

    #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 голосов
/ 03 ноября 2018

Посмотрите на эту строку this.Dispatcher.Invoke(() =>

Dispatcher.Invoke - это синхронный вызов, он блокирует выполнение потока до его завершения. Элемент управления не вернется к вызывающему объекту до тех пор, пока не вернется обратный вызов, поэтому он вызывает неотзывчивый графический интерфейс.

Возможно, вы захотите использовать Dispatcher.BeginInvoke, который является асинхронной операцией, вместо Dispatcher.Invoke ( пример ). Или используйте Dispatcher.Invoke , только если вам действительно нужно изменить или обновить содержимое пользовательского интерфейса. Пример,

Dispatcher.Invoke(() =>
{
    w.Username = null;
    w.Password = null;
});
0 голосов
/ 03 ноября 2018

Оба ответа выше верны. Но, возможно, исправление вашего кода сделает вещи более понятными. Вы должны отделить пользовательский интерфейс от задач, как предложено выше и как показано ниже. Надеюсь, у меня нет синтаксических ошибок, так как я просто изменил его без IDE. По сути, я изменил GetAccounts, чтобы иметь дело только с базой данных, и позволил PopulateMethodAsync работать с пользовательским интерфейсом. Это означает, что GetAccounts будет работать в фоновом режиме, и когда это будет сделано, он передаст результат в раздел пользовательского интерфейса (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();
    }

Надеюсь, это ответит на ваш вопрос

0 голосов
/ 03 ноября 2018

Вы повесили свою программу, используя Dispatcher.Invoke () внутри метода задачи.

Dispatcher.Invoke () заставляет код выполняться синхронно в потоке пользовательского интерфейса WPF и не возвращается, пока этот код не будет завершен. В то же время, внутри вашей «асинхронной кнопки» код ожидает завершения задачи, и вот ваш тупик.

Вам не нужен Task.Run с Dispatcher.Invoke.

Вы должны сделать что-то вроде этого:

  1. Создайте и покажите свою форму.
  2. await Task.Run - получить данные из базы данных, но ничего не вставлять в пользовательский интерфейс. Вы можете вернуть значения в простой класс и использовать для создания типизированной задачи.
  3. Заполните пользовательский интерфейс значениями, возвращенными из базы данных.

Если вы покажете больше кода, я могу быть более точным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...