Example to use 'System.Activities.Statements.StateMachine' class in C# or VB.NET

3k views Asked by At

I feel in the need to ask for a full qualified example usage of the System.Activities.Statements.StateMachine class to store and restore the state of a Control instance (this means, I would like to store the state of a Control to replace the typical undo/redo methodology based on control properties and "commands").

I've been searching for home-made state-machine implementations on Google, I found a lot, but then I discovered this implementation of Microsoft in the .NET Framework Class Library (then now I have no reason to depend on any home-made implementation to reinvent the wheel), however, the MSDN has not a code sample to introduce on the usage of that class, and I didn't found any result on Google that demonstrates its usage (and the little pieces of code samples that I seen in the MSDN on some other related members I didn't understood it at all how do I should use them).

Then now I'm literally blind, trying to learn how to use that class and its related members by trial-and-error.

This below is what I tried by the moment, I'm stuck at the intent to "register" the state of the obj variable, concretelly at the System.Activities.OutArgument.Set and System.Activities.OutArgument.Get methods that takes a ActivityContext as first parameter and I don't know what value I should pass to them (in my code below a call to those methods throws an exception because the value cannot be null).

C# (translated by an online code translator, can have syntax errors):

using System.Activities;
using System.Activities.Statements;

// Create a container for statemachines
StateMachine sm = new StateMachine();

// Declare an object to test its state...
string obj = null;

// Modify the state of 'obj'.
obj = "hello";

// Save 1st state of 'obj'.
Activity<string> act1 = obj;
act1.Result = new OutArgument<string>();
act1.Result.Set(null, obj);
State state1 = new State();
state1.Entry = act1;

// Modify the state of 'obj'.
obj = "hello world";

// Save 2nd state of 'obj'.
Activity<string> act2 = obj;
act2.Result = new OutArgument<string>();
act2.Result.Set(null, obj);
State state2 = new State();
state2.Entry = act2;

// Add saved states into the statemachine collection.
sm.States.Add(state1);
sm.States.Add(state2);

// Modify the state of 'obj'.
obj = string.Empty;

// Restore last saved state of 'obj'.
obj = ((Activity<string>)sm.States.Last().Entry).Result.Get(null);

VB.NET:

Imports System.Activities
Imports System.Activities.Statements

' Create a container for statemachines
Dim sm As New StateMachine()

' Declare an object to test its state...
Dim obj As String

' Modify the state of 'obj'.
obj = "hello"

' Save 1st state of 'obj'.
Dim act1 As Activity(Of String) = obj
act1.Result = New OutArgument(Of String)
act1.Result.Set(Nothing, obj)
Dim state1 As New State()
state1.Entry = act1

' Modify the state of 'obj'.
obj = "hello world"

' Save 2nd state of 'obj'.
Dim act2 As Activity(Of String) = obj
act2.Result = New OutArgument(Of String)
act2.Result.Set(Nothing, obj)
Dim state2 As New State()
state2.Entry = act2

' Add saved states into the statemachine collection.
sm.States.Add(state1)
sm.States.Add(state2)

' Modify the state of 'obj'.
obj = String.Empty

' Restore last saved state of 'obj'.
obj = DirectCast(sm.States.Last().Entry, Activity(Of String)).Result.Get(Nothing)

...Also some instructions like Activity<string> act1 = obj; / Dim act1 As Activity(Of String) = obj I'm not sure if that is the right manner to do it.

PS: Note that in the code above I've used a String variable just to simplify things, but I require to save and restore the state of a Control as I explained before.

1

There are 1 answers

2
Peter Bons On BEST ANSWER

The System.Activities namespace belongs to the Windows Workflow Foundation. Activity classes in this namespace are used to build workflows, like SharePoint workflows for example.

The StateMachine class is a container for several child activities that together form a State Machine Workflow.

Once you have defined a workflow you can run it using the Workflow Engine using a WorkflowInvoker or a WorkflowApplication. From the docs:

WorkflowInvoker provides a simple way for invoking a workflow as if it were a method call and can be used only for workflows that do not use persistence. WorkflowApplication provides a richer model for executing workflows that includes notification of life-cycle events, execution control, bookmark resumption, and persistence.

The ActivityContext you refer to holds information about the workflow runtime, e.g. the host that executes the activity. The runtime fills in the information so you cannot inject something yourself.

The reason that you won't find much examples of using the StateMachine class is that most workflows are build using a graphical designer that creates .XAML files and I don't think many are build using code only.

Now, given all of this you can see that for your scenario this is not a good fit and certainly not designed for undo/redo use cases.

There are framework/libraries that might be a better fit, like this from PostSharp.