我正在努力掌握C#和WPF中的线程特别。
问题背景:
我有一个MVVM应用程序,它具有很长的身份验证过程(几秒钟)。我想让UI保持负责(保持应用程序窗口可拖动和可调整大小 - 显示带有gif元素的预加载器)。
为此,我将所有UI元素和数据库检索分开。之后 - 我已将A后台工作程序实现到登录视图中。
以下是登录视图的代码:
private void ValidateLogin()
{
Usuario user = new Usuario();
MainWindow mw = Window.GetWindow(this) as MainWindow;
mw.preloaderShow();
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (o, args) =>
{
user = _viewmodel.Login(tbLogin.Text, tbPassword.Password); //TimeConsuming DataRetrieval from DB
};
bw.RunWorkerCompleted += (o, args) =>
{
if (user != null)
{
if (user.Activo == 0)
{
mw.preloaderHide();
CustomMessageBox WrongLoginMessage = new CustomMessageBox("El usuario esta inactivo.");
WrongLoginMessage.ShowDialog();
}
else
{
AppSession.Instance.SetValue("currentuser", user);
btnProceed.Visibility = Visibility.Visible;
mw.preloaderHide();
}
}
};
bw.RunWorkerAsync();
}
问题:
显然我在bw.DoWork上陷入僵局,因为“调用线程无法访问此对象,因为不同的线程拥有它。”。
的问题:
1。由于我没有更新bw.DoWork()中的任何UI(此时我们将此视为事实), - 为什么后台工作人员忙?我的意思是 - 正如我所理解的那样,整个概念被引入以在尽可能少的痛苦中在分离的线程中运行进程?
2。如何在保持UI响应的同时从数据库中检索用户?也许BackgroundWorker不是实现这一目标的最佳概念(Task / TaskFactory)?
非常感谢帮助我解决这个问题。 提前谢谢。
答案 0 :(得分:2)
简单的拇指规则是无法从后台线程访问UI元素。您正在访问DoWork中的文本框和密码控制,这会导致异常。
在UI线程上获取用户名和密码,你很好。
string userName = tbLogin.Text;
string password = tbPassword.Password;
bw.DoWork += (o, args) =>
{
user = _viewmodel.Login(userName, password);
};
答案 1 :(得分:1)
private async void ValidateLogin()
{
MainWindow mw = Window.GetWindow(this) as MainWindow;
mw.preloaderShow();
Task<Usuario> taskLogin = Login(tbLogin.Text, tbPassword.Password);
await taskLogin;
Usuario user = taskLogin.Result;
if (user != null)
{
if (user.Activo == 0)
{
mw.preloaderHide();
CustomMessageBox WrongLoginMessage = new CustomMessageBox("El usuario esta inactivo.");
WrongLoginMessage.ShowDialog();
}
else
{
AppSession.Instance.SetValue("currentuser", user);
btnProceed.Visibility = Visibility.Visible;
mw.preloaderHide();
}
}
}
public Task<Usuario> Login(string loginText, string password)
{
return Task.Run(() =>
{
return new Usuario();
});
}
使用Task而不是backgroundworker。