开发者

Using an instance as on item in ToolboxControl in WF rehosted debugging interface

开发者 https://www.devze.com 2023-01-21 16:53 出处:网络
I\'m creating an application that rehost workflow designer. What I did is following the tutorial from Apress\' Pro WF 4 books.

I'm creating an application that rehost workflow designer. What I did is following the tutorial from Apress' Pro WF 4 books.

The principle of the tutorial is:

1. Use WorkflowDesigner class to read workflow xaml file, and bind WorkflowDesigner.View and PropertyView property into ContentControl in the UI.

2. Use System.Activities.Presentation.Toolbox.ToolboxControl class to create VS-like Toolbox so that user can drag-and-drop whatever activities that added into this toolbox

3. ToolboxControl uses ToolboxCategory and ToolboxItemWrapper to construct its content.

Okay, my question is here related to ToolboxItemWrapper class. Based on the documentation, the constructor is using a Class Type, not an Instance. So when we drag and drop, it will instantiate the class into an instance.

Here is the docume开发者_如何学Pythonntation:

http://msdn.microsoft.com/en-us/library/system.activities.presentation.toolbox.toolboxitemwrapper.aspx

However, what I want to hack ToolboxItemWrapper so that it can accept an instance, then when we drag and drop it into WorkflowDesigner.View, the View will show the instance.

Any idea or clues how to achieve this functionality?

Reason why I need this feature:

We want to make it easier for user when adding an 'instance' into the designer. when you have a 'type' in toolbox, after dragging and dropping you need to setup the parameter. When we have 'instance' in toolbox, what user needs to do is just dragging and dropping and that's all. No need to enter parameter to set the 'type'. Less steps for user when creating their workflow.

Another constraint is the list of activities in the toolbox depends on a specific module. This specific module will generate a list of instances. Then I want to convert these generated instances into entries in toolbox. I'll add this info on the questions


It sounds like you need to use the IActivityTemplateFactory interface. In that case the Create() method is called when an activity is dragged onto the designer and you can set properties etc in the activity instance you return. This is what is used when you drag a ReceiveAndSendReply activity pair onto the design surface.


After doing some investigation, Reflection and IActivityTemplate can help to overcome the instance constraint.

The sample code are below, credit to Anders Liu from MSDN Forum

  • Write a class called DynamicActivityTemplate that implement IActivityTemplateFactory. Its impelementation looks like:

        public abstract class DynamicActivityTemplateFactory : IActivityTemplateFactory
         {
          public virtual string GetActivity()
          {
           return null;
          }
    
          public System.Activities.Activity Create(System.Windows.DependencyObject target)
          {
           return XamlServices.Load(new StringReader(GetActivity())) as Activity;
          }
         }

  • When you get your generated activity instances, for each of them, you need dynamically create a Type that inherite from DynamicActivityTemplateFactory. Every type override the method GetActivity() and returns its instance's xaml. Following is a sample of how to create such dynamic type:

    
       AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("GeneratedActivities"), AssemblyBuilderAccess.RunAndSave);
       ModuleBuilder mb = ab.DefineDynamicModule("GeneratedActivities", "GeneratedActivities.dll");
       TypeBuilder tb = mb.DefineType("ActivityTemplateFactory4Sequence", TypeAttributes.Public | TypeAttributes.Class, typeof(DynamicActivityTemplateFactory));
       MethodBuilder methodb = tb.DefineMethod("GetActivity", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), null);
       ILGenerator msil = methodb.GetILGenerator();
       msil.Emit(OpCodes.Ldstr, XamlServices.Save(new Sequence() { DisplayName = "Test" }));
       msil.Emit(OpCodes.Ret);
       Type t = tb.CreateType();
       ab.Save("GeneratedActivities.dll");
       Assembly.Load(new AssemblyName("GeneratedActivities"));

    toolbox.Categories[0].Add(new ToolboxItemWrapper(t));

  • Add those dynamic generated types to toolbox.

    In this case, you create factory types for each of those instances, and then use these factories in toolbox. These factorys will create activities when they are droped to designer. I think this would work for your case, hope it helps.

  • Original post from MSDN forum: http://social.msdn.microsoft.com/Forums/en-US/wfprerelease/thread/1b756014-72a0-483f-99ef-4f9e6e2e2324

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消