none
XAML from Vistual Studio Workflow Designer compared with XAML from rehosted workflow designer RRS feed

  • Question

  • Hello,

    When I author a workflow using the workflow designer in Visual Studio 2010, then the generated XAML is generally something like this:

    <Activity mc:Ignorable="sap" x:Class="WorkflowConsoleApplication1.Workflow1" <!-- much more attributes in here --> >
      <x:Members>
        <x:Property Name="Fred" Type="InArgument(x:String)" /> <!-- example argument -->
      </x:Members>
      <mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
      <Flowchart <!-- various attributes here --> >
          <!-- more stuff in here -->
      </Flowchart>
    </Activity>

    If instead I rehost the designer in a standalone application, I write code like this:

                _wd = new WorkflowDesigner();
                _wd.Load(new ActivityBuilder { Implementation = new Flowchart() });

    I use the ActivityBuilder class so that I will have access to the Variables and Arguments buttons in the designer.  I then proceed to add a 'Fred' argument to the workflow using the rehosted designer.  I then use the following statement to write out the XAML representation of the workflow:

                  string workflowAsXAML = XamlServices.Save(_wd.Context.Services.GetService<ModelTreeManager>().Root.GetCurrentValue())

    The resulting XAML looks like this:

    <ActivityBuilder Name="{x:Null}" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:msd="clr-namespace:Microsoft.Samples.DesignerRehosting;assembly=DesignerRehosting" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <ActivityBuilder.Properties>
            <DynamicActivityProperty Name="Fred" Type="InArgument(x:String)" />
        </ActivityBuilder.Properties>
        <Flowchart>
            <Flowchart.StartNode>
                <x:Null />
            </Flowchart.StartNode>
        </Flowchart>
    </ActivityBuilder>

    I tried to take the above XAML and dump it into a .XAML file in a VS workflow project, and try to compile the project, but things fail pretty quickly with the error message:

    error MC3071: 'InArgument(x' is an undeclared namespace.

    Is it unreasonable to expect that the XAML I take from my rehosted designer would work in a VS workflow project?  If not, how do I resolve the above problem?

    Thanks,

    Notre

    Wednesday, December 9, 2009 6:46 PM

Answers

  • Right, so the reference to S.A.P. would be adding a reference to System.Activities.Presentation in the project, which would include it at build time, which would mean that the sap: namespace would be resolved.

    As far as stripping out the XML directive, I think one of hte overloads to create a XamlXmlWriter takes in an XmlWriter.  I'm pretty sure there is a knob on XmlWriterSettings that will let you omit the directive.

    As far as adding the mc:Ignorable directive, we have some code in an internal type derived from XamlXmlWriter which collects all of the namespaces through WriteNamespace() and then overrides WriteStartObject to output the mc:Ignorable instruction. 

    mc:Ignorable basically tells the XAML reader on the other end to not worry if it can't find types from that namespace. 

    Let me know if that helps,

    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Thursday, December 10, 2009 6:08 PM
    Thursday, December 10, 2009 12:04 AM

All replies

  • Notre,

    The problem is that you are using XamlServices.Save which will just save the instance as is (in which case you get <ActivityBuilder... ).  Can you try using ActivityXamlServices.Save which should result in the <Activity x:class xaml that you see in the designer.  

    Alternatively, you could call WorkflowDesigner.Save.


    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    Wednesday, December 9, 2009 7:08 PM
  • Thanks Matt - this gets me much closer.   I didn't find a Save method on ActivityXamlServices class.  But I did find a CreateBuilderWriter method.  Reviewing your blog post, I figured out how to use this, I think. I modified my code to look like this:

                ActivityBuilder activityBuilder = (ActivityBuilder)_wd.Context.Services.GetService<ModelTreeManager>().Root.GetCurrentValue();
               
                StringBuilder sb = new StringBuilder(); 
                StringWriter tw = new StringWriter(sb);
                XamlWriter xw = ActivityXamlServices.CreateBuilderWriter( new XamlXmlWriter(tw, new XamlSchemaContext()));
                XamlServices.Save(xw, activityBuilder);
                string serializedActivityBuilder = sb.ToString();

    When I take the serializedActivityBuilder string, it looks a bit like this (after manually removing the beginning XML directive):

    <Activity x:Class="WorkflowConsoleApplication1.Workflow2" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:msd="clr-namespace:Microsoft.Samples.DesignerRehosting;assembly=DesignerRehosting" xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <x:Members>
            <x:Property Name="Fred" Type="InArgument(x:String)" />
        </x:Members>
        <mva:VisualBasic.Settings>Assembly references and imported namespaces serialized as XML namespaces</mva:VisualBasic.Settings>
        <Flowchart sap:VirtualizedContainerService.HintSize="614,636">
     <-- body of workflow here -->
        </Flowchart>
    </Activity>

    This looks a lot closer to the VS generate XAML, to be sure.  However, when I try to compile, I still run into one error:

    -- Unrecognized tag 'x:Members' in namespace 'http://schemas.microsoft.com/winfx/2006/xaml'. Note that tag names are case sensitive. Line 2 Position 4

    Any further tips?

    (Edit: Fixed many problems by assigning the Name property of the ActivityBuilder).

    Thanks,

    Notre

    • Edited by Notre Wednesday, December 9, 2009 9:02 PM Fixed null class error
    Wednesday, December 9, 2009 8:40 PM
  • I made another change, after comparing the vanilla VS workflow1.xaml file against the workflow2.xaml file I added myself (and pasted the XML from the previous submission).  I changed the "Build Action" on the workflow2.xaml file properties from "Page" to "XamlAppDef", as this is what was used in the vanilla VS workflow file. 

    After making this change and recompiling the project, the error message about "unrecognized tag 'x:Members..' disappeared.  Unfortunately, it was replaced with the following new error messages:

    - Could not resolve attachable member '{http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation}VirtualizedContainerService.HintSize'
    - Could not resolve attachable member '{http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation}WorkflowViewStateService.ViewState

    I think I'm close! Any further suggestions?

    Thanks,

    Notre
    Wednesday, December 9, 2009 9:10 PM
  • I think you would have two options.  Either add a reference to S.A.P. for the build, or do what the WF designer does which is to add the mc:Ignorable="sap"  directive in the xaml.

    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    Wednesday, December 9, 2009 9:23 PM
  • I'm not sure what a reference to SAP would be???, but I was just about to post using the mc:Ignorable directive in the XAML, as I just came to the same conclusion.

    If I manually modify the XAML so that it starts with this:

    <Activity mc:Ignorable="sap" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    then all goes well!

    Thank you, thank you!

    Now, the final question is how to I add the mc:Ignorable directive and strip out the XML directive (the <?xml version="1.0" encoding="utf-16"?>) programmatically?

    Thank you again,
    Notre

    Wednesday, December 9, 2009 9:30 PM
  • Right, so the reference to S.A.P. would be adding a reference to System.Activities.Presentation in the project, which would include it at build time, which would mean that the sap: namespace would be resolved.

    As far as stripping out the XML directive, I think one of hte overloads to create a XamlXmlWriter takes in an XmlWriter.  I'm pretty sure there is a knob on XmlWriterSettings that will let you omit the directive.

    As far as adding the mc:Ignorable directive, we have some code in an internal type derived from XamlXmlWriter which collects all of the namespaces through WriteNamespace() and then overrides WriteStartObject to output the mc:Ignorable instruction. 

    mc:Ignorable basically tells the XAML reader on the other end to not worry if it can't find types from that namespace. 

    Let me know if that helps,

    matt
    Program Manager -- wf designer -- http://blogs.msdn.com/mwinkle
    • Marked as answer by Notre Thursday, December 10, 2009 6:08 PM
    Thursday, December 10, 2009 12:04 AM
  • Thanks Matt, that completely makes sense on all the points you listed.   Your explanation and tips are invaluable.

    Notre
    Thursday, December 10, 2009 6:08 PM