2016-11-02 7 views
0



Ich versuche mein Bestes mit Mastering Threading in C# und in WPF besonders.
Hintergrund des Problems:
Ich habe eine MVVM-Anwendung, die einen langen Authentifizierungsprozess (einige Sekunden lang) haben. Ich möchte die UI verantwortlich halten (das App-Fenster lässt sich auch ziehen und skalieren, preloader kann mit einem gif-Element angezeigt werden). Um das zu erreichen - habe ich alle UI-Elemente und DB-Retrievals getrennt. Danach habe ich den A-Hintergrundarbeiter in die Login-Ansicht implementiert. Hier
Korrekte Verwendung von BackgroundWorker in WPF

ist der Code der Anmeldung Ausblick:

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

Problem:
Offensichtlich ich in eine Sackgasse bin fallen, auf dem bw.DoWork, denn „Der aufrufende Thread nicht zugreifen kann dieses Objekt, weil ein anderer Thread es besitzt.

Fragen:
1. Da ich keine UI in der bw.DoWork bin Aktualisierung() (halten dies in diesem Moment als Tatsache lässt), - warum ist der Hintergrund Arbeiter beschäftigt? Ich meine - wie ich verstanden habe, dass die gesamte Konzeption eingeführt wurde, um Prozesse in einem getrennten Thread mit möglichst wenig Schmerzen auszuführen?
2. Wie kann man den Benutzer aus der Datenbank abrufen, während die Benutzeroberfläche ansprechbar bleibt? Vielleicht ist BackgroundWorker nicht das beste Konzept um dieses Ziel zu erreichen (Task/TaskFactory)?

Wird sehr geschätzt mit mir auf diesem eine zu helfen. Vielen Dank im Voraus.

+0

Ich kann einfach über den Grund von Downvote gues. –

+1

Sie sollten wirklich solche alten und schweren Objekte wie 'BackgroundWorker' in WPF-Lösung vermeiden. – VMAtm

+0

@VMAtm Ich kann verstehen, was Sie zu sagen versuchen, aber es wäre viel nützlicher, wenn Sie sagen würden, welche Lösung Sie empfehlen (Task?). –

Antwort

2

Einfache Daumenregel ist kann nicht auf UI-Element von Hintergrund Thread zugreifen. Sie greifen in DoWork auf die Textbox und die Passwortkontrolle zu, was zu einer Ausnahme führt.

Holen Sie den Benutzernamen und das Passwort auf dem UI-Thread und Sie sind gut.

string userName = tbLogin.Text; 
string password = tbPassword.Password; 
bw.DoWork += (o, args) => 
{ 
    user = _viewmodel.Login(userName, password); 
}; 
+1

Mein Freund - das ist die Lösung. Was ich gelernt habe - Sie können nicht nur die Benutzeroberfläche aktualisieren, sondern mit der Benutzeroberfläche von BackgrounWorker interagieren. Vielen Dank. –

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

Verwenden Sie den Task statt Background.

+0

Was wäre der wesentliche Vorteil der Verwendung von Task stattdessen? (Ich meine es ernst - funktioniert es schneller/leichter) –

+0

Weitere Informationen [hier] (http://stackoverflow.com/questions/3513432/task-parallel-library-replacement-for-backgroundworker). – remarkies

+1

Ich mag nicht die Art, wie Sie den Hintergrundarbeiter (Syntax) schreiben müssen. Der Code sieht viel sauberer aus, wenn Sie eine Aufgabe verwenden. Es gibt keine großen Vorteile bei der Verwendung der Aufgabe. Es verwendet neuere API und führt asynchrone Prozeduren besser aus. Wenn es schneller ist oder nicht weiß ich nicht. – remarkies