To use State Tracking with WorkflowApplication

Download Sample Tracking State Machine
  1. Create an instance of the root activity
  2. Create an instance of StateMachineStateTracker passing in the root activity
  3. Create an instance of StateTrackerPersistenceProvider passing in the StateMachineStateTracker instance
  4. Add the StateMachineStateTracker and StateTrackerPersistenceProvider to the WorkflowApplication.Extensions

Step 1: Create an instance of the root activity

We recommend creating a readonly static for best performance
internal static readonly Workflow1 Workflow1Definition = new Workflow1();

Step 2: Create an instance of StateMachineStateTracker passing in the root activity

Note: You can also load an instate of StateMachineStateTracker from the InstanceStore
public WorkflowInstance(IWorkflowView view, StateMachineStateTracker stateMachineStateTracker = null)
{
    this.view = view;
    this.StateTracker = stateMachineStateTracker ?? new StateMachineStateTracker(Workflow1Definition);
}

Step 3: Add the StateMachineStateTracker and StateTrackerPersistenceProvider to the WorkflowApplication.Extensions

private void CreateWorkflowApplication()
{
    this.Host = new WorkflowApplication(Workflow1Definition)
        {
            Idle = this.view.OnIdle, 
            Aborted = this.view.OnAbort, 
            Completed = this.view.OnComplete, 
            InstanceStore = this.view.InstanceStore, 
            OnUnhandledException = this.view.OnUnhandledException, 
            PersistableIdle = this.view.PersistableIdle, 
            Unloaded = this.view.OnUnload
        };

    // Setup tracking in UI
    this.Host.Extensions.Add(new MainWindow.TextTracker());
    this.Host.Extensions.Add(this.StateTracker);

    // Setup the persistence participant
    this.Host.Extensions.Add(new StateTrackerPersistenceProvider(this.StateTracker));
}

How do I determine which StateMachine is active?

In WF4, a workflow may have multiple StateMachines. However, only one of them is active at a time.
The StateMachineStateTracker keeps track of all state machines in the workflow in a dictionary that uses the display name of the StateMachine as a key.
Note: Be sure to use unique names for each StateMachine activity or the tracker will not be able to track them properly
// Get the name of the currently active StateMachine
Console.WriteLine(StateTracker.CurrentStateMachine);

How do I know what state the currently active state machine is in?

When the Workflow changes state in a StateMachine, a tracking record of type StateMachineStateRecord is emitted. This tracking record is captured by the StateMachineStateTracker. To access the last known state of the state machine
// Get the current state of the currently active StateMachine
Console.WriteLine(StateTracker.CurrentState);

How do I know what the possible transitions are?

To determine last known set of possible transitions
// Get a comma delimited list of display names for possible transitions for the current state
Console.WriteLine(StateTracker.PossibleTransitions);

foreach(var transition in StateTracker.Transitions)
{
   // Access the Transition and the trigger activity
   Console.WriteLine(transition.Trigger.DisplayName)
}

How is the state tracking information persisted in the instance store?

The StateTrackerPersistenceProvider class creates an XML document with the list of state machines and transitions. This document is stored in the InstancePromotedPropertiesTable and is accessible via the InstancePromotedProperties view. The persistence particpant stores values as follows
Promotion Name: StateTracker
Value1: XML Document
Value2: Activity ID
Value3: Display Name
<StateMachines CurrentStateMachine="StateMachine">
  <StateMachine Name="StateMachine" CurrentState="State2">
    <Transition>T3</Transition>
    <Transition>T5</Transition>
  </StateMachine>
</StateMachines>

How do I initialize a state tracker from a persisted instance?

Use the StateMachineStateTracker.LoadInstances method to return a collection of all StateMachineStateTracker Instances found for the given activity definition.
internal WorkflowModel(IWorkflowView view)
{
    this.view = view;
    this.Workflows = new ObservableCollection<WorkflowInstance>();
    var instances = StateMachineStateTracker.LoadInstances(
        WorkflowInstance.Workflow1Definition, view.ConnectionString);

    if (instances != null)
    {
        foreach (var stateMachineStateTracker in instances)
        {
            this.Workflows.Add(new WorkflowInstance(this.view, stateMachineStateTracker));
        }

        Trace.WriteLine(
            string.Format(
                "Loaded {0} instance{1} from instance store",
                this.Workflows.Count,
                this.Workflows.Count != 1 ? "s" : string.Empty));
    }
    else
    {
        Trace.WriteLine("Error loading instances - be sure to create the SampleInstanceStore database first");
    }
}

Last edited Apr 9, 2012 at 8:56 PM by ronjacobs, version 2

Comments

Norritt Jul 16, 2012 at 12:35 PM 
How can I access variables declared in state machine (or workflow)&
Thanx in advance.