命令型コードを使用してワークフローを作成する方法

このトピックの内容は、Windows Workflow Foundation 4 に該当します。

ワークフロー定義は、構成済みのアクティビティ オブジェクトのツリーです。このアクティビティ ツリーは、手動で XAML を編集したり、ワークフロー デザイナーを使用して XAML を生成したりするなど、多くの方法で定義することができます。ただし、XAML の使用は必須ではありません。ワークフロー定義は、プログラムで作成することもできます。このトピックでは、コードを使用したワークフロー定義の作成の概要について説明します。

ワークフロー定義の作成

アクティビティ型のインスタンスをインスタンス化して、アクティビティ オブジェクトのプロパティを構成することで、ワークフロー定義を作成できます。子アクティビティを含まないアクティビティの場合、数行のコードを使用してこれを作成できます。

Activity wf = new WriteLine
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);
Ee358749.note(ja-jp,VS.100).gif注 :
このトピックの例では WorkflowInvoker を使用してサンプル ワークフローを実行します。ワークフローの呼び出し、引数の受け渡し、および使用可能なさまざまなホストの選択詳細情報、「WorkflowInvoker と WorkflowApplication の使用」を参照してください。

次の例では、1 つの WriteLine アクティビティから成るワークフローを作成します。WriteLine アクティビティの Text 引数が設定され、ワークフローが呼び出されます。アクティビティに子アクティビティが含まれる場合も、作成のメソッドは同じです。次の例では、2 つの WriteLine アクティビティを含む Sequence アクティビティを使用します。

Activity wf = new Sequence
{
    Activities =
    {
        new WriteLine
        {
            Text = "Hello"
        },
        new WriteLine
        {
            Text = "World."
        }
    }
};

WorkflowInvoker.Invoke(wf);

オブジェクト初期化子の使用

このトピックの例では、オブジェクトの初期化の構文を使用します。オブジェクトの初期化の構文は、コードでワークフロー定義を作成する場合に便利な方法です。これは、ワークフローのアクティビティの階層ビューが提供され、アクティビティ間の関係が示されるためです。プログラムからワークフローを作成する場合に、オブジェクトの初期化の構文を使用しなければならないという要件はありません。次の例は、機能的には前のサンプルと同じです。

WriteLine hello = new WriteLine();
hello.Text = "Hello";

WriteLine world = new WriteLine();
world.Text = "World";

Sequence wf = new Sequence();
wf.Activities.Add(hello);
wf.Activities.Add(world);

WorkflowInvoker.Invoke(wf);

オブジェクト初期化子詳細情報、「方法 : コンストラクターを呼び出さずにオブジェクトを初期化する (C# プログラミング ガイド)」および「方法 : オブジェクト初期化子を使用してオブジェクトを宣言する」を参照してください。

変数、リテラル値、および式の使用

コードを使用してワークフロー定義を作成する場合は、ワークフロー定義の作成の一部としてコードが実行する内容、およびそのワークフローのインスタンスの実行の一部としてコードが実行する内容に注意してください。たとえば、次のワークフローはランダムな数値を生成し、それをコンソールに出力します。

Variable<int> n = new Variable<int>
{
    Name = "n"
};

Activity wf = new Sequence
{
    Variables = { n },
    Activities =
    {
        new Assign<int>
        {
            To = n,
            Value = new Random().Next(1, 101)
        },
        new WriteLine
        {
            Text = new InArgument<string>((env) => "The number is " + n.Get(env))
        }
    }
};

このワークフロー定義のコードが実行されると、Random.Next への呼び出しが実行され、その結果がリテラル値としてワークフロー定義に保存されます。このワークフローの多くのインスタンスを呼び出すことができ、そのすべてに同じ数字が表示されます。ワークフローの実行中にランダムな数値を生成するには、ワークフローを実行するたびに評価する式を使用する必要があります。

new Assign<int>
{
    To = n,
    Value = new VisualBasicValue<int>("New Random().Next(1, 101)")
}

VisualBasicValue は式で右辺値として使用できる Visual Basic の構文の式を表し、含まれるアクティビティが実行されるたびに評価されます。式の結果はワークフローの変数 n に代入され、これらの結果はワークフローの次のアクティビティによって使用されます。実行時にワークフローの変数 n の値にアクセスするには、ActivityContext が必要です。次のようなラムダ式を使用するとアクセスできます。

new WriteLine
{
    Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}

ラムダ式は XAML 形式にシリアル化できません。この式に XAML との互換性を持たせるには、次の例に示すように ExpressionServices および Convert を使用します。

new WriteLine
{
    //Text = new InArgument<string>((env) => "The number is " + n.Get(env))
    Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
}

VisualBasicValue を使用することもできます。

new WriteLine
{
    //Text = new InArgument<string>((env) => "The number is " + n.Get(env))
    //Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
    Text = new VisualBasicValue<string>("\"The number is \" + n.ToString()")
}

式詳細情報、「」を参照してください。

引数と動的なアクティビティ

アクティビティをアクティビティ ツリーにまとめてプロパティと引数を構成すると、コードでワークフロー定義を作成できます。既存の引数を見つけることはできますが、新しい引数をアクティビティに追加することはできません。これには、ルート アクティビティに渡されるワークフロー引数が含まれます。ワークフロー引数は、命令型コードでは新しい CLR 型のプロパティとして指定され、XAML では x:Class および x:Member を使用して宣言されます。ワークフロー定義がメモリ内オブジェクトのツリーとして作成された場合は新しい CRL 型が作成されないため、引数を追加できません。ただし、DynamicActivity に引数を追加することはできます。次の例では、2 つの整数の引数を取り、それを一緒に追加して結果を返す DynamicActivity を作成します。各引数に対して DynamicActivityProperty が作成され、操作の結果が DynamicActivityResult 引数に代入されます。

InArgument<int> Operand1 = new InArgument<int>();
InArgument<int> Operand2 = new InArgument<int>();

DynamicActivity<int> wf = new DynamicActivity<int>
{
    Properties =
    {
        new DynamicActivityProperty
        {
            Name = "Operand1",
            Type = typeof(InArgument<int>),
            Value = Operand1
        },
        new DynamicActivityProperty
        {
            Name = "Operand2",
            Type = typeof(InArgument<int>),
            Value = Operand2
        }
    },

    Implementation = () => new Sequence
    {
        Activities = 
        {
            new Assign<int>
            {
                To = new ArgumentReference<int> { ArgumentName = "Result" },
                Value = new InArgument<int>((env) => Operand1.Get(env) + Operand2.Get(env))
            }
        }
    }
};

Dictionary<string, object> wfParams = new Dictionary<string, object>
{
    { "Operand1", 25 },
    { "Operand2", 15 }
};

int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);

動的なアクティビティ詳細情報、「実行時における DynamicActivity を使用したアクティビティの作成」を参照してください。