0

I have a problem with my async method in WPF application. I want to implement asynch await pattern in my WPF application to retain form responsiveness when querying database with EntityFramework. I did everything as described in microsoft examples but it doesn't return control flow to the application as example applications do.

Here is my button click code:

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());
    }
}

Here is my LoginAsync method:

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;
}

I've seen the same usage of async/await in Microsoft example applications, however, their WPF apps return control to Window handle, i.e. I can move window around when in my app that is impossible.

What I want to achieve is using async/await pattern with WPF application to retain responsiveness of application. I want to display loading circle when querying database and return to method when querying has been completed.

Anyone has an idea what am I doing wrong?

4

4 回答 4

0

我有异步加载方法的主要形式:

私有异步无效 MainMenu_Load(object sender, EventArgs e) { await _connection.Start(); 等待 _myHub.Invoke("加入"); _myHub.On("收到", data => { 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();

            }
        });

    }
于 2014-03-19T05:46:26.960 回答
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;
            }
        }
于 2013-11-06T22:16:31.280 回答
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 的异步方法无关。

于 2013-11-04T06:23:41.867 回答
0

如果我理解正确

 Switcher.Switch(new Loader());

是显示“加载圈”的内容。

您需要在登录之前调用它。await就像现在一样,您的处理程序在LoginAsync返回后执行其他所有操作。

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

于 2013-11-03T19:50:12.340 回答