异步方法不会返回控制流以形成

时间:2013-11-03 19:28:31

标签: c# wpf entity-framework asynchronous async-await

我的WPF应用程序中的异步方法有问题。我想在我的WPF应用程序中实现asynch await模式,以便在使用EntityFramework查询数据库时保持表单响应。我按照微软示例中的描述完成了所有操作,但它没有像应用程序那样将控制流返回给应用程序。

这是我的按钮点击代码:

private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
    var loggedIn = await _gluUserRepository.LoginAsync(LoginTextBox.Text, PasswordTextBox.Text);

    Switcher.Switch(new Loader());
    if (loggedIn)
    {
        UserName = LoginTextBox.Text;
        Switcher.Switch(new Blank());
    }
    else
    {
        UserName = String.Empty;
        MessageBox.Show("Błędny login lub hasło. Spróbuj ponownie.");
        Switcher.Switch(new Login());
    }
}

这是我的LoginAsync方法:

public async Task<bool> LoginAsync(string login, string password)
{
    string hashedPassword = PasswordHasher.Hash(password);
    var user = await _dbContext.Users.FirstOrDefaultAsync(x => x.UserName == login);
    if (user != null && user.Password == hashedPassword)
        return true;
    return false;
}

我在Microsoft示例应用程序中看到了async / await的相同用法,但是,他们的WPF应用程序将控制权返回给Window句柄,即我可以在我的应用程序中移动窗口,这是不可能的。

我想要实现的是在WPF应用程序中使用async / await模式来保持应用程序的响应能力。我想在查询数据库时显示加载圈,并在查询完成后返回方法。

任何人都知道我做错了什么?

4 个答案:

答案 0 :(得分:0)

如果我理解正确

 Switcher.Switch(new Loader());

显示'加载圈'。

您需要在<{>>之前将其称为 await登录。就像现在一样,你的处理程序在LoginAsync返回后执行其他所有操作。

您可能还想查看ReactiveUI。它提供了一个解决问题的有用框架。

答案 1 :(得分:0)

很难做出猜测,但请尝试更改LoginButton_Click代码的开头以启动任务,然后await更改其结果,如下所示:

private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
    var loggedInTask = _gluUserRepository.LoginAsync(LoginTextBox.Text, PasswordTextBox.Text);

    MessageBox.Show("before await");
    var loggedIn = await loggedInTask;
    MessageBox.Show("after await");

    // ...
}

你应该看到两个消息框,一个接一个,它们都应该响应,即可移动和可点击。如果你确实看到了这样的行为,那么问题最有可能出现在Switcher.Switch上,与EntityFramework的异步方法无关。

答案 2 :(得分:0)

我找到了解决方案。虽然我不知道为什么它确实有效。但它不会阻止UI线程。我不认为它也是线程安全的,你应该让我们感到厌倦。

private async void LoginButton_Click(object sender, RoutedEventArgs e)
        {
            var loginTask = userRepository.LoginAsync(LoginTextBox.Text, PasswordTextBox.Password);
            controller.DisplayPageLoader();
            DbUser loginResult = await loginTask;
            if (loginResult != null)
            {
                controller.DisplayPageNewMeal();
                controller.SetLoggedUser(loginResult);
            }
            else
            {
                MessageBox.Show("Błędny login lub hasło. Spróbuj ponownie.");
                controller.DisplayPageLogin();
            }
        }

然后在存储库

public Task<DbUser> LoginAsync(string login, string password)
        {
            return Task.Run<DbUser>( () => Login(login, password));
        }

private DbUser Login(string login, string password)
        {
            try
            {
                string hashedPassword = PasswordHasher.Hash(password);
                var user = _dbContext.Users.FirstOrDefaultAsync(x => x.UserName == login);
                if (user.Result != null && user.Result.Password == hashedPassword)
                    return user.Result;
                return null;
            }
            catch(Exception ex)
            {
                _logger.Error("Blad logowania uzytkownika", ex);
                return null;
            }
        }

答案 3 :(得分:0)

我有使用异步加载方法的主窗体:

private async void MainMenu_Load(object sender,EventArgs e)         {             await _connection.Start();             await _myHub.Invoke(&#34; Join&#34;);             _myHub.On(&#34;收到&#34;,data =&gt;             {                 var obj = JsonConvert.DeserializeObject(data);

            messagewindows = new SendMessage(User, obj.Sender);


                 if ((obj.Reciever == User ) )
                 {
                    messagewindows. txtHistory.Text += obj.Sender + " :" + obj.text + Environment.NewLine;
                    messagewindows.Show();
                 }



        });

    }

我显示了显示消息的第二种形式,但是表单挂起崩溃应用程序:

private async void SendMessage_Load(object sender,EventArgs e)         {             Text = Reciever;

        await _connection.Start();
        await _myHub.Invoke("Join");



        _myHub.On("recieved", data =>
        {
            var obj = JsonConvert.DeserializeObject<MessageSent>(data);
            if ((obj.Reciever == Sender || obj.Sender == Sender) && (obj.Sender == Reciever || obj.Reciever == Reciever))
            {


                    txtHistory.Text += obj.Sender + " :" + obj.text + Environment.NewLine;

                    txtHistory.SelectionStart = txtHistory.Text.Length;
                    txtHistory.ScrollToCaret();

            }
        });

    }