在WPF中正确使用BackgroundWorker

时间:2016-11-02 19:08:11

标签: c# wpf multithreading backgroundworker



我正在努力掌握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)?

非常感谢帮助我解决这个问题。 提前谢谢。

2 个答案:

答案 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。