Je travaille sur une application qui a un formulaire principal avec une barre d'état en bas. La barre d'état contient une barre de progression (ProgressBar) et une étiquette (Label) que je veux utiliser pour montrer à l'utilisateur la progression actuelle d'un travail en cours. La barre d'état contient également une étiquette que je souhaite utiliser comme un bouton d'annulation cliquable.
J'ai déjà créé des interfaces asynchrones comme celle-ci, mais elles étaient toujours basées sur une seule action, et en utilisant un travailleur en arrière-plan. Mais dans ce nouveau programme, il y a un certain nombre d'actions différentes que l'utilisateur peut déclencher et pour lesquelles je veux utiliser la même barre d'état pour montrer la progression. J'essaie donc de trouver un moyen de généraliser et de standardiser l'interface de ces contrôles de rapport de progression dans la barre d'état.
Dans certains cas, les processus asynchrones sont créés à l'aide d'un BackGroundWorker, mais dans d'autres cas, je dois créer et gérer les threads secondaires directement.
Voici un code squelette à moitié terminé de ce que j'ai pensé :
public partial class MyForm: System.Windows.Forms.Form
{
...SNIP...
private void WorkProgressChanged(Object sender, EventArgs args)
{
ProgressChangedEventArgs backgroundWorkerArgs = args as ProgressChangedEventArgs;
ProgressReport formReport = args as ProgressReport; //my own custom progress report class
//tries to cast args to a Background worker args
if (backgroundWorkerArgs != null)
{
// update UI based on backgroundWorkerArgs
}
else if (formReport != null)
{
// update UI basd on formReport
}
else
{
//couldn't figure out what kind of progress report was sent
//update UI based on args.ToString();
}
}
private void cancelButtonToolStripLabel_Click(object sender, EventArgs e)
{
//calls cancel method of current processing
if (this._currentWorkCancelAction != null)
{
_currentWorkCancelAction(); //envoke cancel requet
cancelButtonToolStripLabel.Text = "Canceling"; //shows user that cancel request was made
_currentWorkCancelAction = null; //disaccociates cancel button to prevent user from canceling twice
}
}
private void WorkProcessCompleted(Object sender, EventArgs args)
{
//Reset cancel button
cancelButtonToolStripLabel.Text = "Cancel";
cancelButtonToolStripLabel.Visible = false;
//resets the status label and progress bar
statusToolStripLabel.Text = "";
toolStripProgressBar.Value = 0;
}
....SNIP
}
La barre d'état est donc mise à jour en souscrivant à l'événement `WorkProgressChanged(Object sender, EventArgs args) ', et finalement réinitialisée lorsque 'WorkProcessCompleted(Object sender, EventArgs args)' est invoqué par un événement d'achèvement. Mon étiquette d'annulation (bouton) doit également être associée puis dissociée d'une méthode déléguée qui demandera l'annulation du travail en cours.
Ainsi, chaque fois qu'un travail est effectué, un certain nombre de choses doivent se produire. Les abonnements aux événements sont ajoutés/supprimés, les références des délégués sont modifiées, etc. etc. Je me suis donc demandé s'il n'y avait pas un moyen d'encapsuler toutes ces actions dans une ou deux méthodes réutilisables plutôt que d'écrire du code en double pour chaque action qui peut avoir lieu.
Les InitWorkProcess()
La méthode ci-dessous montre comment je pense que cela peut fonctionner. Bien que je sois presque sûr que ce n'est pas la bonne façon d'utiliser la classe EventDescriptor, je n'ai pas trouvé d'autre moyen de référencer un événement en tant que paramètre de méthode. Je n'ai pas trouvé d'autre moyen de référencer un événement en tant que paramètre d'une méthode. Peut-être n'est-ce pas possible ?
public void InitWorkProcess(EventDescriptor workProgressChangedEvent, EventDescriptor workCompletedEvent, System.Action requestCancel)
{
//subscribe to progress changed
workProgressChangedEvent.AddEventHandler(this, this.WorkProgressChanged);
this._workProgressChangedEvent = workProgressChangedEvent;
//subscribe to process completed
workCompletedEvent.AddEventHandler(this, this.WorkProcessCompleted);
this._workCompletedEvent = workCompletedEvent;
//enable cancel button
if (requestCancel != null)
{
cancelButtonToolStripLabel.Visible = true;
this._currentWorkCancelAction = requestCancel;
}
}
... et je modifierais la méthode de gestion de l'événement WorkProgressComplete pour désabonner les relations d'événement lorsque le travail est terminé.
private void WorkProcessCompleted(Object sender, EventArgs args)
{
//Reset cancel button
cancelButtonToolStripLabel.Text = "Cancel";
cancelButtonToolStripLabel.Visible = false;
//resets the status label and progress bar
statusToolStripLabel.Text = "";
toolStripProgressBar.Value = 0;
//unsubscribes WorkProcessCompleted() and WorkProgressChanged() methods
this._workCompletedEvent.RemoveEventHandler(this, this._workCompletedEvent);
this._workCompletedEvent = null;
this._workProgressChangedEvent.RemoveEventHandler(this, this._workProgressChangedEvent);
this._workProgressChangedEvent = null;
}
Quelqu'un a-t-il des suggestions sur la manière de procéder ? Devrais-je simplement oublier le InitWorkProcess()
et ajouter/supprimer toutes les relations événement/délégué séparément pour chaque action ? Ou existe-t-il une meilleure méthode ?