2016-08-25 1 views
0

Vous ne savez pas quel était le meilleur titre.Conditions d'écran, de filetage et de course

J'ai des problèmes avec mon fil. Dans le Application_Startup je commence un nouveau thread qui ouvre une fenêtre d'écran de démarrage simple à l'aide d'une classe d'assistance statique. En Application_Startup il y a une méthode qui vérifie si l'utilisateur s'est connecté ou pas et ouvre ensuite une fenêtre de connexion s'il n'est pas déjà connecté. À ce stade, si la fenêtre de connexion apparaît, l'écran de démarrage devrait close, mais ce n'est pas le cas.

private void Application_Startup(object sender, StartupEventArgs e) 
    { 
     Thread thread = new Thread(
     new ThreadStart(
      delegate() 
      { 
       SplashScreenHelper.SplashScreen = new Splash() 
       // this works. the splash screen opens 
       SplashScreenHelper.Show(); 
       System.Windows.Threading.Dispatcher.Run(); 
      } 
     )); 
     thread.SetApartmentState(ApartmentState.STA); 
     thread.IsBackground = true; 
     thread.Start(); 

     check(); 
    } 


    private void check() 
    { 
     var clientid = (int) IPdevices.Properties.Settings.Default["clientid"]; 
     if (clientid > 0) 
     { 
      try 
      { 
       // this works 
       SplashScreenHelper.ShowText("Looking for profile..."); 
      } 
      catch (EntityException) 
      { 
      } 
     } 
     else 
     { 
      // This does not work 
      SplashScreenHelper.Close(); 
      // this opens up fine. 
      openLoginWindow(); 
     } 
    } 

Les choses commencent à échouer lorsque nous avons atteint la condition else dans la méthode check. Pour commencer, j'ai mis un point de rupture dans le SplashScreenHelper.Close(); et j'ai trouvé que l'instance de Splash est nulle et donc le Close provenant de la fenêtre Splash, ne se déclenche jamais (voir la classe ci-dessous). Mais ce qui est curieux, c'est comment peut-il être nul s'il a été correctement instancié et que la fenêtre d'écran de démarrage est affichée?

est ici la SplashScreenHelper classe pour avoir une idée:

class SplashScreenHelper 
{ 
     public static Splash SplashScreen { get; set; } 

     public static void Show() 
     { 
      if (SplashScreen != null) 
      { 
       SplashScreen.Show(); 
      }  
     } 

     public static void Close() 
     { 
      if (SplashScreen == null) return; 
      if (!SplashScreen.Dispatcher.CheckAccess()) 
      { 
       SplashScreen.Dispatcher.Invoke(DispatcherPriority.Normal, 
        new Action(delegate() 
        { 
         System.Windows.Threading.Dispatcher.CurrentDispatcher.InvokeShutdown(); 
         SplashScreen.Close(); 
        })); 
      } 
      else 
      { 
       SplashScreen.Close(); 
      } 
     } 

     public static void ShowText(string text) 
     { 
      if (SplashScreen == null) return; 

      if (!SplashScreen.Dispatcher.CheckAccess()) 
      { 
       SplashScreen.Dispatcher.Invoke(
        DispatcherPriority.Normal, 

        new Action(delegate() 
        { 
((SplashScreenViewModel)SplashScreen.DataContext).SplashScreenText = text; 
        } 
       )); 
      } 
      else 
      { 
       ((SplashScreenViewModel)SplashScreen.DataContext).SplashScreenText = text; 
      } 

     } 
    } 

Lorsque nous avons atteint ce else, j'ai deux fenêtres: la fenêtre de l'écran d'accueil et la fenêtre de connexion, bien que la fenêtre de démarrage aurait été fermé, mais il ne pas parce que l'instance de l'écran de démarrage est null et c'est là que je ne peux pas comprendre ce qui se passe. Ce que je pense est que la méthode check se déclenche avant que le thread ne démarre, ouvre la fenêtre de connexion, frappe l'instruction else, essaie de fermer l'écran de démarrage mais ce thread n'a jamais démarré et ne l'a jamais instancié. Puis, le thread instancie finalement l'écran de démarrage après tout cela.

+0

Est-ce que votre écran de démarrage fait quoi que ce soit? Si non, pourquoi ne pas simplement utiliser le mécanisme intégré et éviter le mal de tête? https://msdn.microsoft.com/en-us/library/cc656886(v=vs.110).aspx – Will

+0

Eh bien, il affiche des informations à l'utilisateur à tout moment, les barres de progression de chargement du module et il comprend également une notice de copyright et la version publishone en haut. – Dimitri

Répondre

0

Vous devez vous assurer que la première partie du code de votre deuxième thread s'exécute avant d'appeler check.

ManualResetEvent s sont parfaits pour cela!

using (ManualResetEvent mre = new ManualResetEvent(false)) 
{ 
    Thread thread = new Thread(new ThreadStart(
     delegate() 
     { 
      SplashScreenHelper.SplashScreen = new Splash() 
      // this works. the splash screen opens 
      SplashScreenHelper.Show(); 
      mre.Set(); // signal that we are done setting up the splash screen 
      System.Windows.Threading.Dispatcher.Run(); 
     } 
    )); 
    thread.SetApartmentState(ApartmentState.STA); 
    thread.IsBackground = true; 
    thread.Start(); 

    mre.WaitOne(); // wait until the signal is received 
} 

check(); // now we can safely call check() 
+0

Je vais essayer – Dimitri