2009-08-26 9 views
2

Voici une méthode que je souhaite expédier dans un environnement de travail d'arrière-plan, mais j'ai du mal à la faire en fonction de la méthode créée. Comme vous le pouvez, il ne renvoie rien qui soit correct mais attend un objet directoryInfo chaque fois qu'il est rappelé.Utilisation d'un travailleur en arrière-plan - Mise à jour d'un ProgressBar sur la progression d'une méthode récursive

private void getSizeForTargetDirectory(DirectoryInfo dtar) 
    { 
     // generate a collection of objects. files comes first and then directories. 

     foreach (Object item in collection) 
     { 
      if (item == file) 
      { 
       track the size of the files as you encounter. 
      } 
      else if (item == directory) 
      { 
       // found a new directory, recall the method. !!! 
      } 
     } 
    } 

Ceci est ma première fois à l'aide d'un travailleur de fond, donc je suis un peu coincé, j'ai essayé quelque chose mise en œuvre grâce à l'aide trouvée ici, mais quand je me suis coincé réalisé ma méthode était récursive.

How do I display progress during a busy loop?

I mis en œuvre une méthode de gestionnaire d'événements DoWork mais on a remarqué que je avais besoin de rappeler en quelque sorte la méthode si j'avais plusieurs fichiers et dossiers à traiter sur les niveaux de sous inférieurs.

J'ai un simple gestionnaire d'événements de clic de bouton qui appelle ma méthode 'getSizeForTargetDirectory()' lorsque le noeud sélectionné est un répertoire.

private void retrieveInfoButton_Click(object sender, EventArgs e) 
    { 
     // check to see if the path is valid 
     // reset the labels and textfields. 
     string fullPath = treeDrives.SelectedNode.FullPath; 
     string sNodesName = treeDrives.SelectedNode.Text; 

     if (directory) // Enter here if its a directory. 
     { 
      string parentPath = treeDrives.SelectedNode.Parent.FullPath; 
      DirectoryInfo[] dirArray = populateFoldersArray(parentPath); 

      for (int i = 0; i < dirArray.Length; i++) 
      { 
       if (dirArray[i].Name == sNodesName) 
       { 
        getSizeForTargetDirectory(dirArray[i]); 

        // do work ! 

Espérons que cela explique ce que j'essaie de faire et comment je le fais. La question est de savoir comment puis-je utiliser la fonctionnalité de progression du rapport de la classe de travailleurs en arrière-plan lorsque la majeure partie du travail que j'essaie d'expédier provient d'une méthode récursive. Grâce aux tests précoces, j'ai remarqué que ma méthode getSize était incroyablement efficace après quelques ajustements et des informations de taille rapportées pour le dossier actuellement fourni, mais j'utilise une machine de développement assez puissante, ce qui peut ne pas être vrai pour tous les utilisateurs .

Merci pour la lecture, j'espère que quelqu'un peut aider !!!

Répondre

3

Je pense qu'il est beaucoup plus simple d'utiliser les méthodes intégrées de chaque Directory ou DirectoryInfo pour obtenir tous les répertoires ou fichiers, en utilisant l'option de recherche récursive:

public partial class Form1 : Form 
{ 
    private Action<float> updateProgMethod; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     updateProgMethod = UpdateProgress; 
    } 

    private void GetDirectorySizeAsync(string path) 
    { 
     backgroundWorker.RunWorkerAsync(path); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     DirectoryInfo di = new DirectoryInfo((string)e.Argument); 
     di.GetTotalSize(ProgressCallback); 
    } 

    // Takes callbacks from the GetTotalSize() method 
    private void ProgressCallback(float p) 
    { 
     // Invokes update progress bar on GUI thread: 
     this.BeginInvoke(updateProgMethod, new object[] { p }); 
    } 

    // Actually updates the progress bar: 
    private void UpdateProgress(float p) 
    { 
     progressBar.Value = (int)(p * (progressBar.Maximum - progressBar.Minimum)) + progressBar.Minimum; 
    } 
} 

public static class IOExtensions 
{ 
    public static long GetTotalSize(this DirectoryInfo directory, Action<float> progressCallback) 
    { 
     FileInfo[] files = directory.GetFiles("*.*", SearchOption.AllDirectories); 
     long sum = 0; 
     int countDown = 0; 
     for (int i = 0; i < files.Length; i++) 
     { 
      sum += files[i].Length; 
      countDown--; 
      if (progressCallback != null && countDown <= 0) 
      { 
       countDown = 100; 
       progressCallback((float)i/files.Length); 
      } 
     } 
     return sum; 
    } 
} 

Il est difficile de deviner les progrès sans le savoir le nombre de fichiers ou de dossiers en premier!

EDIT: J'ai amélioré le code un peu.

+1

Bonjour cecil ... question? C'est un morceau de code intéressant ... cela signifie-t-il que d'un objet directoryInfo donné je peux utiliser les options de recherche pour retourner tous les fichiers sous un répertoire donné? Dans les deux cas, je vais devoir essayer ça car ça change tout !!! – IbrarMumtaz

+1

Oui. Et cela n'augmente pas le temps d'exécution si vous comptez énumérer chaque fichier de toute façon. –

+0

Très utile. Implémenté dans WPVM MVVM et fonctionnant magnifiquement. –

2

Si, quand vous appelez une méthode, vous ne savez pas combien de temps la méthode va prendre ou combien de pas discrets vont être impliqués, alors il n'y a aucun moyen d'afficher une barre de progression pendant que la méthode est en cours d'exécution. À mon avis, le but d'une barre de progression n'est pas de donner des informations fiables sur le moment où une tâche va être achevée. Au contraire, le but est d'empêcher l'utilisateur de paniquer et d'annuler toute l'opération car il pense que votre programme s'est bloqué et qu'il ne fait rien du tout.

Comme vous parcourez les répertoires et les sous-répertoires, une approche plus simple consiste à afficher simplement le répertoire courant dans une étiquette. Cela donnerait à l'utilisateur un sentiment de détente que les choses se passent, et si les répertoires sont tous classés par ordre alphabétique, ils peuvent même évaluer eux-mêmes la progression globale de l'opération.

+0

N'oubliez pas d'ajouter une de ces jolies choses à roues tournantes! – Pondidum

+0

@Andy: J'ai toujours aimé ce que faisait Netscape - ils avaient une barre de progression qui avançait vers la droite, et quand elle arrivait là, elle s'inversait et avançait vers la gauche, et ainsi de suite ad infinitum. – MusiGenesis

+0

Cela fait beaucoup de sens que je suis assez nouveau pour le codage C# donc la première réponse m'a un peu effrayé. Bien que j'aime l'idée de mettre à jour une simple étiquette. Plusieurs options sont soudainement venues à l'esprit. TY – IbrarMumtaz

0

Je voudrais signaler à quel point vous avez obtenu puisque vous ne connaissez pas le but jusqu'à ce que vous y arrivez. Je le ferais une fois par invocation. Peut-être le nombre de fichiers et le nombre de répertoires vus jusqu'à présent.

+0

Ma méthode originale permet de suivre le nombre de fichiers et de répertoires vus jusqu'à présent ... le rapport que j'ai trouvé est une avenue assez plausible à explorer. TIA – IbrarMumtaz