Dans le post précédent, je traitais de l’affichage d’un assistant quand un utilisateur fait un double-click sur une activité d’un workflow. Mais il restait le cas du drag&drop à traiter.

Drag&Drop et VS 2005

On est là dans le cas le plus simple. Il faut créer un objet de type ToolboxItemAttribute, surcharger CreateComponentsWithUI et décorer la classe d’activité désirée.

En pratique :

    [Serializable]

    public class YourServiceToolboxItem : ActivityToolboxItem

    {

        public YourServiceToolboxItem(Type type)

            : base(type)

        {

        }

 

        private YourServiceToolboxItem(SerializationInfo info, StreamingContext context)

        {

            base.Deserialize(info, context);

        }

 

        public override IComponent[] CreateComponentsWithUI(IDesignerHost host)

        {

            IComponent[] componentArray1 = base.CreateComponentsWithUI(host);

            // Do your stuff here

            return componentArray1;

        }

    }

 

    [Category("Windows Workflow")]

    [ToolboxItem(typeof(YourServiceToolboxItem))]

    public partial class YourServiceActivity : Activity

    {

    }

 

Simple, rapide, mais avec la version Beta, si vous hébergez le designer, cela ne marche pas. Soit c’est un bug de la beta, soit je suis passer à coté de quelque chose…

En attendant, une solution transitoire pour vos activités

Drag&Drop et application Windows Form

Une première solution consiste à intercepter l’ajout de composants au niveau du designer. Après avoir instancier votre DesignSurface et votre WorkflowView, récuperez le service IComponentChangeService :

IComponentChangeService changeService = GetService(typeof(IComponentChangeService)) as IComponentChangeService;

if (changeService != null)

{

                        changeService.ComponentAdded += new ComponentEventHandler(changeService_ComponentAdded);

 }

Dans le gestionnaire d’événement, par réflexion, vous pourrez accéder à l’attribut ToolboxItem pour appeler vous-même la méthode CreateComponentsWithUI :

            MemberInfo inf = null;

            object[] attributes = null;

 

            Activity activity = e.Component as Activity;

 

            inf = activity.GetType();

 

            attributes = inf.GetCustomAttributes(typeof(ToolboxItemAttribute), false);

            if (attributes.Length == 1)

            {

                ToolboxItemAttribute attribute = (ToolboxItemAttribute)attributes[0];

 

                Type[] typesArray = new Type[1];

                typesArray[0] = System.Type.GetType("System.Type");

                ConstructorInfo info = attribute.ToolboxItemType.GetConstructor(typesArray);

 

                object[] parameters = new object[1];

                parameters[0] = activity.GetType();

                ActivityToolboxItem item = info.Invoke(parameters) as ActivityToolboxItem;

 

 

                // solution 1

                IDesignerHost designerHost = GetService(typeof(IDesignerHost)) as IDesignerHost;

                IComponent[] components = item.CreateComponentsWithUI(designerHost);

                Activity newActivity = components[0] as Activity;

 

Le soucis est que vous avez instancier ici une nouvelle activité, distincte de celle créée par le Drag&Drop. Il faut alors soit substituer les activités dans le designer, soit copier les propriétés. Ici, j’ai choisi de copier les DepencyProperty :

                MemberInfo[] mInfo = newActivity.GetType().GetMembers(BindingFlags.Static | BindingFlags.Public);

 

                Type dependencyType = System.Type.GetType("System.Workflow.ComponentModel.DependencyProperty");

                foreach( MemberInfo i in mInfo )

                {

                    FieldInfo fi = newActivity.GetType().GetField(i.Name);

                    if (fi.FieldType.FullName == "System.Workflow.ComponentModel.DependencyProperty")

                    {

                        DependencyProperty dp = fi.GetValue(newActivity) as DependencyProperty;

                        object value = newActivity.GetValue(dp);

                        activity.SetValue(dp, value);

                    }

                }

 

Plutôt pénible, mais le code de l’attribut fonctionne à l’identique sous VS et dans votre application.

 

Deuxième solution, modifier la méthode CreateComponentsWithUI de l’attribut en ajoutant les lignes suivantes (plus des tests de nullité pour blinder le code) :

            // solution 2

            ISelectionService selectionService = ((IServiceProvider)host).GetService(typeof(ISelectionService)) as ISelectionService;

            object test = selectionService.PrimarySelection;

 

Lorsque l’instance de l’attribut ToolboxItem est créé et la méthode CreateComponentsWithUI est appelée, cette dernière recherche alors dans le designer l’élément ajouté en dernier (il est sélectionné par défaut). Reste alors au code à manipuler cet objet plutôt que d’en instancier un nouveau.

En attendant d’avoir une solution plus propre J