2010-02-16 2 views
0

J'ai un service Web avec deux méthodes:Voulez-vous que le gestionnaire d'événements s'exécute une seule fois/Conception de la machine d'état?

RetrieveFirstLevelOptions() et RetrieveSecondLevelOptions (int levelOneOption).

L'interface graphique contient deux zones de liste déroulante: FirstLevelOptionsCombo et SecondLevelOptionsCombo.

J'ai un problème avec la création d'un flux de contrôle pour l'étape d'initialisation lorsque je dois faire une demande à RetrieveFirstLevelOptions() et, une fois les résultats obtenus, appeler RetrieveSecondLevelOptions (par défaut levelOneOption = 0). Le problème est que puisque tout se passe de manière asynchrone, je ne sais pas quelle est la meilleure approche pour permettre que ce comportement se produise une fois et une seule fois, au début.

Une option que j'aimerais tant est d'attacher un deuxième gestionnaire d'événements à l'événement RetieveFirstLevelOptionsCompleted et de le supprimer lui-même après une seule exécution. Mais il semble qu'un tel comportement soit impossible à obtenir.

Une autre option consisterait à avoir un indicateur booléen pour indiquer si dans la phase d'initialisation et si c'est le cas, le gestionnaire de RetrieveFirstLevelOptionsCompleted exécuterait une logique supplémentaire. Cependant, cette idée donne l'impression que tous les gestionnaires d'événements doivent vérifier les informations d'état et faire des choses différentes en fonction de l'état actuel. Cela semble être une mauvaise conception parce que le flux de contrôle semble décentralisé.

Je veux avoir un mécanisme de flux de contrôle centralisé qui prendra les décisions en un seul endroit. Mais comment cela peut-il être fait quand tout est exécuté de manière asynchrone?

+1

Pourquoi le « supprimer le gestionnaire d'événements après avoir exécuté une fois » impossible d'obtenir? –

+0

La citation est "supprimer lui-même après avoir couru qu'une seule fois". Si vous savez comment faire fonctionner ça, j'aimerais beaucoup le voir. Sinon, nous revenons à l'idée de machine d'état. – Rire1979

Répondre

1

"Une option que j'aimerais tant est d'attacher un second gestionnaire d'événements à l'événement RetieveFirstLevelOptionsCompleted et de le supprimer lui-même après une seule exécution, mais il semble qu'un tel comportement soit impossible à obtenir."

Y at-il une raison quelconque cela ne fonctionne pas:

class Example 
{ 
    SomeWebService myService; 

    Example() 
    { 
     // do stuff 
     myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod; 
    } 

    void MyHandlerMethod(object sender, RetrieveFirstLevelOptionsCompletedEventArgs e) 
    { 
     // do stuff 
     myService.RetrieveFirstLevelOptionsCompleted -= MyHandlerMethod; 
     // potentially attach next event handler for all subsequent calls 
     myService.RetrieveFirstLevelOptionsCompleted += MyHandlerMethod2; 
    } 
} 
+0

J'avais l'habitude d'utiliser cette approche, mais cela me semblait toujours un hack. Il y a deux problèmes de base: (1) il est difficile de garder une trace du gestionnaire qui est actuellement attaché, car il étend votre logique dans une variété d'endroits; et (2) s'il vous arrive d'effectuer un second appel à myService.RetrieveFirstLevelOptions avant la fin du premier, vous allez vous retrouver avec des comportements inattendus qui seront très difficiles à déboguer. Un wrapper qui accepte un rappel spécifique est plus facile à comprendre et plus difficile à se tromper. –

+0

Je suis d'accord dans une certaine mesure, mais je pense que la mise en œuvre dépend des spécificités de ce que vous essayez d'atteindre. Cette réponse était plus dirigée vers sa citation disant qu'il n'était pas capable de supprimer un gestionnaire d'événement. Je n'ai pas rencontré trop de situations où c'est une meilleure méthode que même en utilisant un simple si (initialisé) vérifier – jeffora

+0

J'ai eu des problèmes pour supprimer le gestionnaire d'événements, mais j'ai alors réalisé, que la cause est XAML. Il semble que lorsque vous définissez un événement en XAML, vous ne pouvez pas le supprimer facilement avec - = handler. –

1

Le modèle que j'utilise habituellement dans une situation comme celle-ci consiste à créer un wrapper autour de la méthode de proxy de service Web Async qui accepte une méthode de rappel. La méthode de rappel obtient ensuite transmis à la méthode RetrieveFirstLevelOptionsAsync() comme ceci:

public void RetrieveFirstLevelOptions(Action callback) 
{ 
    client.RetrieveFirstLevelOptionsAsync(callback); 
} 

void client_RetrieveFirstLevelOptionsCompleted(object sender, AsyncCompletedEventArgs e) 
{ 
    var callback = e.UserState as Action; 
    if (callback != null) 
    { 
     callback(); 
    } 
} 

Ainsi, lorsque vous appelez RetrieveFirstLevelOptions(), vous passez juste le rappel que vous voulez exécuter une seule fois, et vous ne disposent pas toujours de s'inquiéter de se faire appeler plusieurs fois. Vraisemblablement, vous mettriez votre appel à RetrieveSecondLevelOptions() dans ce rappel.

+0

Si cela ne vous dérange pas de demander, comment ce mécanisme garantit-il que le rappel sera appelé exactement une fois pendant la durée de vie de l'application, dans le cadre de la phase d'initialisation? – Rire1979

+0

En soi, techniquement ce n'est pas le cas. Ma supposition est que c'est seulement une préoccupation car il peut y avoir plusieurs fois que le premier appel est fait (RetrieveFirstLevelOptions), mais vous voulez seulement faire le second appel pendant l'initialisation. (Sinon, pourquoi s'inquiéter?) Donc, dans ce scénario, ce wrapper vous permet d'appeler le premier appel lors de l'initialisation, et soyez sûr que votre deuxième appel (RetrieveSecondLevelOptions) ne sera pas fait à chaque fois que vous devez appeler RetrieveFirstLevelOptions. –

Questions connexes