Office Workflows are designed to be decoupled as much as possible. The Observer Design Pattern is used to decouple an Office Add-in host application from workflow business logic. A Windows Workflow 4.0 Tracking Participant is used as an Activity state subscriber. An Office Add-in acts as a subscriber by instantiating an instance of an activity state Tracking class providing a TrackingProfile. A TrackingProfile filters activity state change as well as argument and variable values. An add-in creates a delegate method to filter ActivityStateRecord properties available in the ActivityStateTrackedEventArgs event argument.

Example ActivityStateTracked

    void sampleParticipant_ActivityStateTracked(object sender, ActivityStateTrackedEventArgs e)
      //Invoke a Treeview method to add all ActivityState names and arguments to Nodes
      if (Globals.ThisAddIn.CustomTaskPanes.Count > 0)
        WorkflowActivitiesControl workflowActivities = Globals.ThisAddIn.CustomTaskPanes[0].Control as WorkflowActivitiesControl;
        workflowActivities.Invoke(new WorkflowActivitiesControl.AddNodeDelegate
          (workflowActivities.AddNode), e.ActivityStateRecord.Activity.Name, e.ActivityStateRecord.Arguments);

      //Filter for Name == "FormattingActivity"
      if (e.ActivityStateRecord.Activity.Name == "FormattingActivity")
        string argColor = (string)e.ActivityStateRecord.Arguments["ArgColor"];
        if (Globals.ThisAddIn.Application.ActiveCell != null)
          Globals.ThisAddIn.Application.ActiveCell.Style = argColor;

To decouple an Office Add-in host

Step 1 – Implement IClientActivity.Run() and set arguments

A client host implements IClientActivity.Run() and passes a Dictionary<string, object> containing workflow arguments to a WorkflowApplication instance. A client runs a workflow by calling the WorkflowApplication.Run() method. WorkflowApplication.Run() is an asynchronous call; therefore, you need to create delegate callback methods for workflow events. For example, a Word add-in could pass ContentControl.Range.Text values.

Note Passing the Office add-in Window Handle allows the workflow to supply .NET forms setting the form parent to the application handle. See LoginFormActivity for an example Workflow client form.
  class SampleActivity : IClientActivity
    public void Run(string workflowPath)
      var inputs = new Dictionary<String, Object>
          {"ArgTitle",  title.Range.Text},
          {"ArgBody",  body.Range.Text},
          {"Handle", System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle}

      Activity wf = (Activity)ActivityXamlServices.Load(workflowPath);

      WorkflowApplication wfApp = new WorkflowApplication(wf, inputs);

Step 2 - Instantiate an instance of a Tracking class

The next step instantiates an instance of a Tracking class providing a TrackingProfile. A TrackingProfile subscribers to certain activity states extracting certain variables and arguments. For this example, the TrackingProfile is interested in all activity states extracting all variable and argument values.

      Tracking sampleParticipant = new Tracking
        TrackingProfile = new TrackingProfile()
          Name = "CustomTrackingProfile",
          Queries = 
            new ActivityStateQuery()
              // Subscribe for track records from all activities for all states
              ActivityName = "*",
              States = { ActivityStates.Closed },

              // Extract workflow variables and arguments as a part of the activity tracking record
              // Variables = "*" allows for extraction of all variables in the scope of the activity
              // Arguments = "*" allows for extraction of all arguments in the scope of the activity
              Variables = 
              { { "*" } },
              Arguments = 
              { { "*" } }

      sampleParticipant.ActivityStateTracked += new Tracking.ActivityStateTrackedHandler(sampleParticipant_ActivityStateTracked);

Step 3 - Create delegate callback methods

A WorkflowApplication.Run() is an Asynchronous call; therefore, you need to create delegate callback methods for workflow events. For this example, the host IClientActivity.Run() method contains a Completed delegate callback method to get the workflow outputs.

      wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs wfe)
        IDictionary<String, Object> output = wfe.Outputs;


Step 4 – Run Workflow

The final step is to run the Workflow.


Example TrackingParticipant_ActivityStateTracked Filter

      if (e.ActivityStateRecord.Activity.Name == "DocumentParts")
        if (e.ActivityStateRecord.Arguments.Keys.Contains("ContentParts"))
          Dictionary<string, string> contentParts = (Dictionary<string, string>)e.ActivityStateRecord.Arguments["ContentParts"];
          foreach(string item in contentParts.Values)
            Globals.ThisAddIn.Application.Selection.TypeText(item + "\r");

Last edited Oct 14, 2011 at 2:03 AM by dvana, version 14


No comments yet.