2010-09-16 15 views
3

Création d'une application .net dans des formulaires C#, Windows. Comment mettre à jour la barre de progression 1 étape à chaque cycle d'une boucle de 100 cycles? (Je traite une feuille Excel dans la boucle.) Les contrôles de la barre de progression se trouvent dans la classe d'interface utilisateur qui se connecte à la classe de contrôleur qui se connecte à une classe personnalisée (modèle MVC). La boucle est dans la classe personnalisée. Dois-je envoyer l'instance de classe d'interface utilisateur dans chaque méthode ou y a-t-il une meilleure solution?Comment mettre à jour la barre de progression en une étape, à chaque cycle de boucle? C#

À l'heure actuelle, la barre de progression est mise à jour une fois la boucle terminée. Application.doevents et .update ou .refresh ne fonctionnent pas.

+2

Qu'est-ce qui ne va pas avec un événement aux niveaux inférieurs qui annonce la progression? – Joey

+0

Désolé, je ne comprends pas ce que vous venez de dire.La barre de progression est définie dans une classe supérieure, si je mets à jour la valeur dans la classe inférieure comment la classe supérieure le sait-elle? Je devrais passer l'instance de la classe ui ou l'instance de la barre de progression aux niveaux inférieurs. –

+0

Je ne suis pas certain, mais si la mise à jour est retardée, cela ressemble presque à un problème de threading. Utilisez-vous invoke (si nécessaire)? –

Répondre

5

Dites le ci-dessous est votre classe responsable de faire le travail avec la boucle en elle. Ajouter un événement pour indiquer votre progression Puis à partir de votre interface utilisateur simplement gérer cet événement et mettre à jour la barre de progression en conséquence.

sealed class Looper 
{ 
    public event EventHandler ProgressUpdated; 

    private int _progress; 
    public int Progress 
    { 
     get { return _progress; } 
     private set 
     { 
      _progress = value; 
      OnProgressUpdated(); 
     } 
    } 

    public void DoLoop() 
    { 
     _progress = 0; 
     for (int i = 0; i < 100; ++i) 
     { 
      Thread.Sleep(100); 
      Progress = i; 
     } 
    } 

    private void OnProgressUpdated() 
    { 
     EventHandler handler = ProgressUpdated; 
     if (handler != null) 
     { 
      handler(this, EventArgs.Empty); 
     } 
    } 
} 

Vous pourriez mettre en œuvre en ayant une BackgroundWorker dans le cadre de l'interface utilisateur, où vous appelez looper.DoLoop() en cas backgroundWorker.DoWork. Ensuite, dans votre gestionnaire pour l'événement looper.ProgressUpdated, vous pouvez appeler backgroundWorker.ReportProgress pour incrémenter votre barre de progression à partir du fil de l'interface utilisateur. Notez qu'il serait probablement plus logique d'inclure la progression elle-même dans les informations portées par votre événement ProgressUpdated (je ne voulais pas écrire une nouvelle classe dérivant de EventArgs pour illustrer cela, vous avez probablement l'image en tous cas).

Notez également que ce qui précède n'a vraiment de sens que si vous exécutez votre code avec la boucle sur un thread distinct du thread de l'interface utilisateur. Sinon, tout votre travail se fait avant la prochaine actualisation de l'interface utilisateur, de sorte que votre barre de progression ne fournira aucune valeur (elle passerait de 0 à 100 une fois la boucle terminée).

Juste un exemple de la façon dont ce genre de chose peut être atteint.

+0

Qu'est-ce qui s'appelle où vous avez la structure publique contrôlant la variable privée? Est-ce l'encapsulation? –

+0

@hi tech credo: Vous voulez dire "Progrès"? C'est juste une propriété .NET, pas une 'struct'. Oui, c'est une partie importante de l'encapsulation ... on dirait qu'il y a probablement beaucoup de choses sur cette réponse qui pourrait être nouvelle pour vous. Faites-moi savoir si vous rencontrez des problèmes ou si vous vous sentez confus et je ferai de mon mieux pour vous aider. –

+0

Ok, donc mon thread principal sera l'exécution de l'interface utilisateur, et j'utilise le travailleur d'arrière-plan pour appeler ma méthode de contrôleur, qui à son tour appelle la méthode en classe personnalisée avec la boucle. Ai-je besoin d'exécuter une boucle dans la classe d'interface utilisateur pour appeler à plusieurs reprises backgroundWorker.ReportProgress? ou met-elle à jour automatiquement? Merci pour votre réponse patient, je n'ai jamais fait de filetage avant. –

1

J'ai généralement une classe qui effectue les vérifications d'invocation sur l'interface utilisateur. UI -> "UpdaterClass" -> autre classe.

La classe Updater possède des méthodes prédéfinies et des références aux contrôles de l'interface utilisateur. Donc Updater.StepProgressBar() est ce que j'appelle à l'étape de la barre de progression de l'interface utilisateur. Je passe la référence de la classe Updater à toute classe qui aura besoin de mettre à jour l'interface utilisateur directement. De cette manière, toutes les mises à jour de l'interface utilisateur provenant de différents threads sont gérées par une seule classe. Ce n'est pas la manière la plus générique de l'implanter, mais elle ne manque jamais.

Exemple psuedocode:

class Updater() 
{ 

    public ProgressBar pb; 

    delegate void UpdateProgressBar(); 

    public StepProgressBar() 
    { 
    if(pb.InvokeRequired) 
    { 
      BeginInvoke(new UpdateProgressBar(this.StepProgressBar); 
    } 
    else 
    { 
      pb.Step(); 
     } 
    } 

} 

Quelque chose comme ça.

+0

Cela ne sera pas pratique pour moi car j'ai un certain nombre de classes de contrôleurs qui accèdent à plus d'une interface utilisateur et chaque contrôleur a plusieurs bibliothèques en dessous. –

1

Vous pouvez utiliser un délégué. Lorsque votre processus d'arrière-plan crée la classe personnalisée, liez un délégué qui est appelé depuis la classe personnalisée pour signaler la mise à jour. Ensuite, vous pouvez réagir à cet appel dans la couche d'interface utilisateur et mettre à jour la barre de progression à partir de là.

par exemple. (Avertissement, psuedocode):

MyCustomClass class = new MyCustomClass(); 
class.ProgressUpdated += (s,e)=>{ /* update UI */}; 
class.StartLoop(); 
+0

euh désolé n'a jamais utilisé les délégués avant, je vais devoir lire sur eux d'abord. –

+0

Quelle est la différence entre délégué, événement et thread? –

+0

@Dan Tao a donné un bon exemple de comment faire cela. Je vous suggère de faire une lecture extérieure sur les événements et les délégués avant d'essayer de le faire. Le traitement en arrière-plan a ses propres pièges que vous devez savoir éviter avant d'entrer dans quelque chose de trop complexe. – Robaticus