[WF 4 (5)] アクティビティ (基礎)


環境 : Visual Studio 2010 Beta 2 (.NET Framework 4)

WF 4

  1. そのアイデアとベースクラスの変更
  2. コードいらずのワークフロー (入門)
  3. ワークフローのコードと XAML の内部
  4. フローチャート (FlowCharts)
  5. アクティビティ (基礎)
  6. アクティビティコンテキスト (context) と変数 (Variable) の意義
  7. アクティビティにおけるさまざまな実行管理
  8. アクティビティのデリゲート
  9. アクティビティの非同期実行
  10. アクティビティデザイナー
  11. ブックマーク
  12. Workflow Extensions と 永続化、トラッキング
  13. デザイナーリホスティングとカスタムアプリケーション

こんにちは。

すみません、月曜、火曜と外出 (-> 帰宅) でシリーズを放置してしまいましたが、今回は、アクティビティの基本について記載したいと思います。

アクティビティの超基本 (カスタムアクティビティの作成)

"コード要らずのワークフロー" とは言え、アクティビティの 1 つ 1 つはまとまった処理が記述された 1 つのコンポーネントです。
例えば、コンソールの文字列を読み込む簡単なカスタムアクティビティを作成して実感してみましょう。

第 2 回のように、[ワークフローコンソールアプリケーション] を作成します。つぎに、[追加] - [新しい項目] で [コードアクティビティ] を選択してカスタムアクティビティを追加します。(今回は、ReadLine という名前にしました。)

コンソールから 1 行読む込むので、作成されるコードファイルで、以下のような処理を記述します。(ここで登場する CodeActivity については、第 1 回を参照してください。)

public sealed class ReadLine : CodeActivity
{
    public InArgument<string> LineText { get; set; }
    public OutArgument<string> InputText { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        Console.WriteLine(context.GetValue(this.LineText));
        string inputText = Console.ReadLine();
        context.SetValue(InputText, inputText);
    }
}

このアクティビティは、LineText と InputText という 2 つの入力用・出力用の引数 (Argument) を持ち、最初に LineText で設定された内容をコンソール出力 (Output) し、ユーザーが入力 (Input) した結果を InputText に設定します。

これでアクティビティの作成は完了です !

この作成したアクティビティを使ってみましょう。リビルドをおこなって、ワークフロー (Workflow1.xaml) を開き、第 2 回の要領で、InputValue という string 型のワークフロー変数 (Variable) を作成して、下図のように、この ReadLine アクティビティ (カスタムアクティビティ) を使ったワークフローを作成してみます。(変なアイコンのしょぼいアクティビティですが、このデザイナーのカスタマイズについては、またいずれご説明します。。。)

実行をおこなうと、コンソール上に「Please input !」と表示され、入力された結果が InputValue のワークフロー変数に設定され、コンソール上に再度 WriteLine されるようになります。(下図)

以前の WF (WF 3 / WF 3.5) のときにも説明してきましたが、ワークフロー作成では、このようにデータの流れ (受け渡し) も入力引数 (InArgument)、出力引数 (OutArgument) を使って宣言的に流れを組み立てます。

さまざまな選択肢

上記ではカスタムアクティビティを コードで 記述しましたが、上図で [コードアクティビティ] のアイテムではなく、[アクティビティ] のアイテムを選択することで、アクティビティを XAML を使用して宣言的 (Declarative) に記述することもできます。この場合、構築方法は、コードを記述するのではなく、第 2 回のワークフロー作成時と同様、デザイナーを使ってアクティビティを組みあわせていきます。(ここでは、WF で言う "宣言的" の意味に注意してください。「処理」が宣言的なのではなく、「記述」が宣言的という意味です。例えば、XAML で Sequence アクティビティを使って実装した処理は、順番を持った「手続き的」な処理になり、処理自身が SQL のような宣言的な処理ということではありません。)

従来の WF でも、XAML を使用したこうしたアクティビティの作成 (= アクティビティを使ったアクティビティの作成) は可能でした。しかし、従来の WF と WF 4 では、同じ "宣言的なアクティビティ" ですが、意味が異なります。従来の WF では、コードを使って Sequence アクティビティを継承し、実際には、その Sequence の中身をデザイナーで構築しました。WF 4 では、振る舞い (アクティビティ) そのものを XAML で記述するという概念 (これは、System.Activities という名前空間の名称からも見てとれます) になっており、Sequence アクティビティを継承せず、XAML 上にいきなり「振る舞い」 (Activity) をデザインするという概念になります。(例えば、WriteLine アクティビティだけの入った宣言型のアクティビティを作成することもできます。)
なお、この宣言型で作成されたアクティビティの親は、CodeActivity や NativeActivity ではなく、大元の Activity クラスになります。(第 1 回を参照)

さらに、アクティビティではジェネリックを使用することができます。例えば、データベースから結果の一覧を取得して返すようなアクティビティを作成する場合、その結果の入れ物の型 (タイプ) を、あらかじめ決めておくのではなく、ジェネリックを使用して (アクティビティの) 利用者に指定させることができます。アクティビティを利用する側 (ワークフローを作成する際) は、下記の通りカスタムなクラスも XAML で記述することもできるため、一貫して XAML による宣言的な記述のみでワークフローを構築することもできます。(無論、シリアライズ可能なクラスとしてコードで記載しても構いません。ただし、"宣言型のワークフロー" と混在させず、別のプロジェクトとして作成しておくと良いでしょう。。。)

<x:Object x:Class="WorkflowConsoleApplicationTest.TestData"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <x:Members>
    <x:Property Name="Id" Type="x:Int32" />
    <x:Property Name="Name" Type="x:String" />
  </x:Members>
</x:Object>

さらに、WF 4 から、アクティビティが返り値を持つことができます。第 1 回では、Activity クラスと、そこから継承された CodeActivity、NativeActivity のみを説明しましたが、Activity クラスから継承されているクラスとして ActivityWithResultActivity というクラスも存在しており、さらにそこから継承されて Activity<TResult> というジェネリックなアクティビティが存在しています。そして、このアクティビティを継承する形で、第 1 回で述べた CodeActivity、NativeActivity、DynamicActivity などに対応する CodeActivity<TResult>、NativeActivity<TResult>、DynamicActivity<TResult> が存在しています。

この "結果を持つアクティビティ" を使用すると、上記で作成したアクティビティは、以下の通り記述できます。つまり、返り値 (OutputArgument) が 1 つしかないアクティビティの場合には、この "結果を持つアクティビティ" を使ってわかりやすい方法で記述することができます。(このアクティビティを使用する際は、上図の「InputText」プロパティが表示される代わりに、「Result」プロパティが表示されます。)

public sealed class ReadLine : CodeActivity<string>
{
    public InArgument<string> LineText { get; set; }

    protected override string Execute(CodeActivityContext context)
    {
        Console.WriteLine(context.GetValue(this.LineText));
        return Console.ReadLine();
    }
}

ここでは、単なる Execute メソッドの実装例ですが、Execute の中で、さらに子アクティビティを呼び出すケースなどでは、子アクティビティの返り値を使った処理などが非常に簡単に (意味的に、わかりやすく) 記述できます。

この返り値を持つアクティビティは、OutArgument を使う方法と何ら "意味的には" 変わりませんが、WF 4 が標準で持っている演算系、集合処理などのプリミティブな標準アクティビティでは返り値を持つアクティビティが使用されていて、第 3 回で紹介したプログラムコードを使ったワークフローでは、VB 式の代わりにこの返り値を持ったアクティビティを使ってプロパティを記述することもできます。

ということで、今回はくだらない話をダラダラと書きすぎましたので、このへんでやめましょう。
次回は、これまでさんざん登場している「InArgument, OutArgument、Variable とかって何 ?」(こんなもん、別に使わんでも良いでしょ !) という質問に答えつつ、もう少し内部のメカニズムに迫りたいと思います。お楽しみに。。。 (誰も楽しんでいないかもしれませんが。。。)

 

Comments (0)

Skip to main content