我的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模式来保持应用程序的响应能力。我想在查询数据库时显示加载圈,并在查询完成后返回方法。
任何人都知道我做错了什么?
答案 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();
}
});
}