2012-03-14 3 views
3

J'ai terminé mon petit projet qui fait un gros travail. J'ai réalisé dans ce court temps de calcul, mon interface graphique se fige. J'ai donc fait quelques recherches et j'ai trouvé ceci =>http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUIDémarrage d'un nouveau thread avec un constructeur

J'ai commencé à implémenter ceci est mon projet, mais j'ai réalisé que cette implémentation particulière ne fonctionnait pas dans mon projet.

Dans mon projet, j'ai beaucoup de classes et un "manager" qui contrôle toutes les autres classes. Si j'initise cette classe Manager, elle fait déjà le gros du travail dans le constructeur.

à ma question:

Comment démarrer i un nouveau thread avec un contructor?

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 

       Manager mgr = new Manager(e, handreader); // here starts the heavy lifting 
       Thread mgrThread = new Thread(new ThreadStart(mgr)); // what to do ? 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 


      } 
     } 

EDIT: j'ai décidé de recoder bien mon programme. maintenant le levage lourd est dans une fonction mais je pense que j'ai fait une erreur.

tout le programme ressemble à ceci:

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 
       Manager mgr = new Manager(e, handreader, txtLog, sl); 
       //sl.Invoke(new MethodInvoker(mgr.test)); 
       sl.Invoke(new MethodInvoker(mgr.test)); // first try 
       Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

      } 
     } 

les sl.Invoke(new MethodInvoker(mgr.test)); // first try œuvres, mais il gèle encore mon interface graphique.

Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

et cette ligne ne fait rien.

ma fonction de test:

public void test() 
    { 
     StringBuilder builder = new StringBuilder(); 
     foreach (PlayerController pc in fm.lPc) 
     { 
      Range range = new Range(handReader.hand, handReader.handversus, pc); 
      builder.Append(pc.getHeroCardsSimple()+" vs 100% range = "+range.vsRange()+"\r\n"); 
     } 
     sl.Text = builder.ToString(); 
    } 

Répondre

3

Vous devriez utiliser une approche différente pour cela. Votre constructeur est toujours appelé sur le thread graphique.

Func<Manager> asyncConstructor; 
    private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e) 
    { 
     asyncConstructor = new Func<Manager>(() => new Manager()); 

     asyncConstructor.BeginInvoke(ManagerConstructed, null); 
    } 

    private void ManagerConstructed(IAsyncResult result) 
    { 
     Manager mgr = asyncConstructor.EndInvoke(result); 
     //we can only access form controls from the GUI thread, 
     //if we are not on the gui thread then 
     //do the changes on the gui thread. 
     if (this.InvokeRequired) 
     { 
      this.Invoke(new Action(() => 
      { 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 
      })); 
     } 
    } 
+1

Même si cela répond à la question principale, je suis d'accord avec Jon: Ne pas faire de lourdes charges dans un constructeur! – ChrFin

+0

Oui, bien sûr, mais c'est une question différente – Bas

2

Déplacer le « soulever des objets lourds » hors du constructeur à une sorte de « travailleur » et exécuter cette méthode dans le thread.

Modifier le gestionnaire:

public Manager(/*params*/) 
{ 
    //params 
    //heavy lifting 
} 

à

public Manager(/*params*/) 
{ 
    //params 
} 

public void DoWork() 
{ 
    //heavy lifting 
} 

et l'appel à

Manager mgr = new Manager(e, handreader); 
Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork)); 
mgrThread.Start(); 

ATTENTION: Si vous accédez à/modifier des éléments de l'interface utilisateur dans le fil, n » t oublier d'invoquer ces appels!

+0

a essayé de mettre en œuvre votre recommandation, mais sans succès vérifié votre –

+0

Il suffit de modifier: Vous avez oublié de lancer le fil! Voir mon edit ... – ChrFin

1

Eh bien, vous pourrait utiliser:

Thread mgrThread = new Thread(() => new Manager(e, handreader)); 

... mais vous ne serez pas une référence au gestionnaire pour le reste de votre code.

Pour être honnête, faire les lourdes charges dans le constructeur est généralement une mauvaise idée de toute façon, pour diverses raisons. Il vaudrait mieux déplacer ce travail ailleurs:

// Constructor just sets things up 
Manager mgr = new Manager(e, handreader); 
// DoWork method does the real work 
Thread mgrThread = new Thread(mgr.DoWork); 
Questions connexes