[WF] Bien utiliser le Load du WorkflowDesigner

Publié le 12 mars 2014 par Jeremy.jeanson

Avec l'arrivée de Workflow Foundation 4, le rehosting du designer a été grandement simplifié. Il n'en reste pas moins que dans certains cas, l'exercice peut devenir périlleux. Cet article n'a pas pour vocation de faire le tour des différents problèmes rencontrés, mais de vous mettre sur les bons rails pour éviter de trop nombreux écueils.

D'expérience, j'ai constaté que le choix fait par les développeurs pour charger leurs workflows dans le designer conditionnait la totalité du code qui en découlait :

  • Complexité.
  • Maintenabilité.
  • Évolutivité.
  • …et bugs…

Pour charger une définition de workflow, le WorkflowDesigner dispose d'une méthode à 3 surcharges. Si on regarde la MSDN on obtient les informations suivantes :

  • Load() : Charge un flux de travail à partir du XAML contenu dans la propriété Text.
  • Load(Object) : Charge un flux de travail à l'instance spécifiée.
  • Load(String) : Charge un flux de travail à partir du XAML contenu dans le fichier spécifié.

En réalité, les choses sont un peu plus complexes. J'ai isolé trois cas de figure qui peuvent devenir très compliqués si on choisit mal sa surcharge :

  1. Plusieurs chargements
  2. Le chargement pour l'affichage
  3. Le chargement pour un usage poussé (tracking visuel, mise à jour dynamique…)

Chacun de ses scénarios induit un usage différent.

1. Plusieurs chargements

Tout d'abord, la méthode Load ne peut être utilisée qu'une seule foi pour un WorkflowDesigner, quelle que soit la surcharge utilisée. Si votre application doit charger plusieurs définitions de suite, il faudra donc oublier l'idée de ne créer qu'une instance de WorkflowDesigner.

Ceci est important, car si votre WorkflowDesigner est lié à de nombreux éléments, il faut relancer le code l'initialisant avant chaque Load.

Dans le cas d'un MVVM, la bonne pratique consiste à stocker le WorkflowDesigner dans un ViewModel. Ce ViewModel aura la responsabilité de créer une nouvelle instance à chaque chargement. Simple éficace et sans problèmes, quelle que soit la surcharge du Load utilisée.

Côté gestion des ressources et performance, il faut être prudent. Même si l'idée d'avoir une instance de ce ViewModel par définition est tentante, il faut se rappeler que les WorkflowDesigner sont gourmands en RAM. Certes, le chargement d'une définition par la méthode Load, n'est pas instantané. Mais il vaut mieux avoir un petit temps de chargement (dont la perception peut être atténuée par une petite animation WPF) qu'une application lourde et peu réactivée. D'autant que l'on évite ainsi les désagréments évoqués dans le point suivant.

2. Le chargement pour l'affichage

Dans le cas où votre unique objectif est d'afficher une définition de workflow, les trois surcharges se valent…. Enfin presque.

La seconde surcharge n'aime pas les DynamiqueActivity. Cela induit des comportements indésirables, tels qu'un design systématiquement réduit. On se retrouve donc bien souvent avec un beau rectangle dont on ne peut rien faire. A éviter en l'état. Il est préférable de lui fournir une Activity préalablement chargée en mémoire ou un ActivityBuilder.

La première et la troisième surcharge sont préférables.

Dans certain cas, où l'interface graphique est chargée sans être visible, il peut y avoir des bugs d'affichage. Il peut être préférable de n'utiliser que la troisième surcharge. Si vos définitions de workflow proviennent d'une base de données, il faudra donc passer par un fichier temporaire. Il n'y a malheureusement pas d'approche plus propre.

3. Le chargement pour un usage poussé (tracking visuel, mise à jour dynamique…)

Dans ce cas, il n'y a pas de secret. La troisième surcharge est la seule qui fonctionne :

  • Pour le tracking visuel, le debug et la map ne fonctionnent qu'avec un fichier.
  • Pour les mises à jour dynamiques, certains attributs ajoutés sur une activité ne sont pas bien interprétés tant que l'activité n'est pas enregistrée dans un fichier xaml.
  • … etc …

La troisième et dernière surcharge est donc préférable pour les scénarios avancés. Même si cela induit la création de fichiers temporaires.

Après avoir rencontré quelques problèmes avec le designer dans Visual Studio et des fichiers temporaires interceptés par un abruti d'antivirus dont je ne citerai pas le nom. J'en ai conclu que ce devait être une approche similaire qui devait être utilisée dans notre IDE favori. Après chaque modification, même si l'on n'enregistre pas notre xaml, un fichier temporaire est créé.

Voilà pour ce petit tour d'horizon d'une méthode qui a déjà fait suer pas mal de développeurs ;)