1

I'm trying to rehost the designer, but every time I slap a workflow into the designer:

_workflowDesigner = new WorkflowDesigner();
// added to UI here
Properties.Content = _workflowDesigner.PropertyInspectorView;
_workflowDesigner.Load(myWorkflowInstance);

where myWorkflowInstance is a workflow defined in a referenced assembly. I have done the magic Register to get the default activity metadata registered:

new DesignerMetadata().Register();

and I've registered all my custom NativeActivities:

public static void Register(IEnumerable<Type> activityTypes)
{            
    // activityTypes are all my custom NativeActivities
    // and all workflows (root of System.Activities.Activity)
    var builder = new AttributeTableBuilder();
    var attrGroups =
        from x in activityTypes
        from y in x.GetCustomAttributes(true).OfType<Attribute>()
        group y by x into g 
        select g;

    foreach (var typeGroup in attrGroups)
        builder.AddCustomAttributes(typeGroup.Key, typeGroup.ToArray());
    MetadataStore.AddAttributeTable(builder.CreateTable());
}

yet, when I load an activity in the designer this is what I get:

Why r u collapsed?

What am I missing here?


I'm thinking it has something to do with the fact that these workflows are compiled and only exist within the Implementation property of an Activity...

2 Answers2

1

Is your workflow instance wrapped in an ActivityBuilder?

Update: Investigating a little further here I found one possible solution using the WorkflowInspectionServices.

var activities = WorkflowInspectionServices.GetActivities(new DemoWorkflow());
designer.Load(activities.First());
Maurice
  • 27,582
  • 5
  • 49
  • 62
  • Nope, I tried doing that, however, and still got the same result. What's the AB for? –  Nov 16 '10 at 15:57
  • The ActivityBuilder creates the root element in the designer. Normally I use a WD.Load(path to XAML) and that works fine. But then I also use the Designer attribute to link Activity with ActivityDesigner. – Maurice Nov 16 '10 at 17:42
  • First, the Activity doesn't have a designer; its a compiled workflow. A workflow doesn't have a Designer attribute, but all the activities you drag into it do have them. I am loading and inspecting activities within an assembly, so I do not have the option of getting the original xaml. All I have are the workflow types and instances of those types. –  Nov 16 '10 at 19:53
  • Thanks much for spending some time on this! This is the first time I've heard of that type, so I much appreciate your help on this. It does behave a little bit strangely, however. When I was testing it, I got a NRE in a call to CacheMetadata in one of my activities. But calling it again wouldn't result in an exception being thrown. I think the Workflow designer and runtime are a bit more careful with badly or hastily written activities. –  Nov 17 '10 at 14:48
0

A bit of reflector and reflection has led me to this travesty:

var impl = (typeof(DemoWorkflow)
            .GetProperty("Implementation", 
                         BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(new DemoWorkflow(), new object[0]) 
            as System.Func<System.Activities.Activity>)();

_workflowDesigner.Load(new ActivityBuilder { Implementation = impl });

Is this it? Seriously? I feel sick knowing that I wrote that. Dirty.

I noticed in reflector that the xaml for the workflow actually is embedded in the assembly in a resource stream: the stream in Reflector

but all attempts to use this failed.

var target = typeof(DemoWorkflow);
var name = string.Format("{0}.obj.Debug.{1}.g.xaml", 
                         target.Assembly.GetName().Name, 
                         target.Name);
Activity derp = null;
using (var stream = assy.Assembly.GetManifestResourceStream(name))
{
    var reader = new XamlXmlReader(stream, new XamlSchemaContext());
    // throws an exception as the property Implementation is in the xaml;
    // it is protected and cannot be set, so deserialization blows up
    derp = ActivityXamlServices.Load(reader);
}

I don't see any other option at this point.

  • The XAMl in the resources is actually slightly different that the XAML in the original file. The root element is no longer Activity but your DemoWorkflow. I have found another solution using the WorkflowInspectionServices, see my other message. – Maurice Nov 17 '10 at 11:40
  • @maurice actually, the xaml in the resources is the serialized root workflow activity; its just that conceptually that root doesn't exist in your mental model of what you've designed. I've since seen you can configure deserialization to not throw when encountering protected/internal serialized properties. –  Nov 17 '10 at 14:52