Question

J'utilise le modèle Model-View-Presenter dans un projet WinForms et l'un des problèmes que je rencontre est le moment où le formulaire indique au présentateur de faire quelque chose, puis ne réagit pas tant que le présentateur passe à fais le. Heureusement, dans mon projet, je n'ai aucun problème à faire en sorte que tous les appels du présentateur soient asynchrones. La question est de savoir comment procéder.

Chaque appel du présentateur devrait-il simplement être encapsulé dans une nouvelle création de fil? *

new Thread(()=>_presenter.DoSomething()).Start();

Quelles sont les meilleures pratiques ici? Que se passe-t-il si l'utilisateur appuie sur une touche "Abandonner ce que vous faites"? bouton? Comment puis-je abandonner gracieusement?

. * En réalité, j'utiliserais probablement une sorte de proxy sur le présentateur plutôt que de placer la création du fil dans le WinForm

Était-ce utile?

La solution

Je ne peux que prétendre que j’y ai pensé (avant de lire votre question;). Je commencerais par truquer les endroits où cela compte vraiment; par exemple le chokepoint d'accès à la base de données. S'il y a un endroit qui ne devrait pas être exécuté dans le "UI" contexte (vous pouvez l'enregistrer à partir de http: // msdn .microsoft.com / fr-fr / library / system.threading.synchronizationcontext.current.aspx dans le thread de l'interface utilisateur, puis compare plus tard au contexte de synchronisation non-UI), puis à Debug.BitchAndMoan (). Tous les calculs plus longs (qui "devraient" être tous clairement séparés dans leurs propres variétés, à droite;) devraient affirmer que.

Je suppose que vous devez au moins rendre le type d'exécution de la fonction de présentateur configurable via un attribut, qui est ensuite obéi par un proxy. (juste au cas où vous voudriez que quelque chose soit fait en série).

L'annulation d'une tâche est en réalité un problème du présentateur, mais vous devez disposer d'un objet de référence indiquant ce que vous souhaitez arrêter. Si vous utilisez le mode proxy, vous pouvez alors sélectionner les threads créés dans la liste des tâches avec celle de IAsyncResult, mais il est toujours difficile de décider laquelle doit être annulée si la même action peut être appelée plusieurs fois en parallèle. Vous devez donc fournir à la tâche un nom spécifique à l'appel approprié lorsque vous la démarrez; ce qui implique beaucoup trop de logique dans View Side - > Le présentateur devrait probablement demander à View de demander à l’utilisateur laquelle des tâches doit être supprimée.

Mon expérience est que ceci est généralement simplement contourné en utilisant des événements (style SCSF). Si je le faisais à partir de zéro, je choisirais la procuration dans la mesure où SCSF a été une source de difficultés si nombreuses que je doute de la santé mentale de ses concepteurs.

Autres conseils

Je place généralement toute action qui peut (de manière réaliste) prendre plus d'une seconde ou deux dans une tâche distincte, quelque chose comme:

public interface ITask
{
    void ExecuteTask (ITaskExecutionContext context);
    void AfterSuccess(ITaskExecutionContext context);
    void AfterFailure(ITaskExecutionContext context);
    void AfterAbortion(ITaskExecutionContext context);
}

J'ai également une abstraction pour exécuter de telles tâches:

public interface ITaskExecutor : IDisposable
{
    void BeginTask(ITask task);
    void TellTaskToStop();
}

Une des implémentations de ce ITaskExecutor utilise BackgroundWorker :

public class BackgroundTaskExecutor : ITaskExecutor
{
    public void BeginTask(ITask task)
    {
        this.task = task;
        worker = new BackgroundWorker ();
        worker.DoWork += WorkerDoWork;
        worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
        worker.WorkerSupportsCancellation = true;

        worker.RunWorkerAsync();
    }

    ...
}

Je compte énormément sur l’injection de dépendance et l’IoC pour câbler les choses ensemble. Dans le présentateur, je viens d'appeler quelque chose comme:

GoAndDontReturnUntilYouBringMeALotOfMoneyTask task = new GoAndDontReturnUntilYouBringMeALotOfMoneyTask(parameters);
taskExecutor.BeginTask(task);

Les boutons Annuler / Abandonner sont ensuite câblés afin d'indiquer à l'exécuteur / à la tâche d'abandonner.

C’est un peu plus complexe que ce qui est présenté ici, mais c’est l’idée générale.

Pourquoi ne pas faire en sorte que le modèle de proxy que vous utilisez accepte quelques rappels pour renvoyer les résultats ou abandonner?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top