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. UseWorkflowDesigner
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.
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
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;
}
}
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));
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
精彩评论