Beginning WF4讀書筆記(二):編碼實現工作流程

來源:互聯網
上載者:User

    在前一篇中,使用工作流程設計工具設計一個相當簡單的工作流程。現在,我們將使用編碼的方式實現與前一篇相同的工作流程。任何一個流程既可以用代碼實現也可以用工作流程設計工具去實現。選擇哪種方式是仁者見仁智者見智的問題。但是使用編碼的方式去實現有利於更好的瞭解流程是如何運作的。

建立一個控制台應用程式

    啟動VS,建立一個簡單的控制台應用程式(請注意這裡沒有使用workflow的模板),2-1所示。

圖2-1.建立一個控制台應用程式

    添加System.Activities引用。這樣你就可以在這個控制台應用程式中使用WF4中的活動了。然後使用下面代碼代替Program.cs檔案上的命名空間。

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

 

    在main()函數中輸入下面代碼:

WorkflowInvoker.Invoke(CreateWorkflow());Console.WriteLine("Press ENTER to exit");Console.ReadLine();

 

    上面和前一篇的main()函數的實現是一樣的。如果你願意,你可以簡單地複製並粘貼前一篇的應用程式的代碼。儘管如此,它們之間還是有點區別。看下面代碼調用的是CreateWorkflow() ,而前一篇調用的是Workflow1()。

WorkflowInvoker.Invoke(CreateWorkflow());

 

    由工作流程設計工具產生的Workflow1被定義在Workflow1.xaml檔案中。CreateWorkflow()是你即將實現的一個方法。

定義工作流程

    正如我在前一篇所說的,一個工作流程只是的嵌套屬性的集合。更準確地說,工作流程是嵌套類和它們的屬性的集合。為了簡化這個過程,我將一次一個層級地向你示範如何去實現它們。首先將下面的方法添加到的Program.cs檔案中:

static Activity CreateWorkflow(){Variable<int> numberBells = new Variable<int>(){Name = "numberBells",Default = DateTime.Now.Hour};Variable<int> counter = new Variable<int>(){Name = "counter",Default = 1};return new Sequence(){};}
CreateWorkflow()方法首先建立了兩個int類型的Variable,分別是numberBells和counter。它們可以供各種活動使用。
CreateWorkflow()方法將返回一個Activity類型的活動。Activity類型是WorkflowInvoker類的Invoke方法需要參數類型。Activity是所有活動的基類,包括Sequence活動。
故返回Sequence執行個體,而CreateWorkflow()方法傳回型別是Activity。
實現層級1
現在,您已經定義了好了一個空的Sequence活動。相當於建立了一個沒有子活動的順序工作流程。現在,在Sequence上面添加幾個子活動,使用清單2-1所示的代碼代替 return new Sequence()
return new Sequence(){DisplayName = "Main Sequence",Variables = { numberBells, counter },Activities ={new WriteLine(){DisplayName = "Hello",Text = "Hello, World!"},new If(){DisplayName = "Adjust for PM"// Code to be added here in Level 2},new While(){DisplayName = "Sound Bells"// Code to be added here in Level 2},new WriteLine(){DisplayName = "Display Time",Text = "The time is: " + DateTime.Now.ToString()},new If(){DisplayName = "Greeting"// Code to be added here in Level 2}}};
此代碼首先定義了Sequence活動的DisplayName屬性和與Sequence相關的Variable對象。然後初始化子活動成員的集合。具體來說,它建立的子活動如表2-1。
 

對於WriteLine活動,還定義Text屬性。至於其餘的活動具體的實現將被定義在下一層級中。

實現層級2

首先,對於If 活動中,輸入以下代碼:

DisplayName = "Adjust for PM",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => numberBells.Get(env) > 12),Then = new Assign<int>(){DisplayName = "Adjust Bells"// Code to be added here in Level 3}

 

這段代碼定義了I活動的Condition屬性和Then屬性(沒有定義Else 分支)。Assign活動具體在下一層級中實現。Condition屬性的定義,需要解釋一下。

Expressions

    ExpressionServices 類的靜態方法Convert<T>() 用來建立InArgument<T> 類。它是Condition屬性需要的類型。這些類和方法使用了泛型(<T>)。所以他們可以使用任何一種資料類型。這裡,我們使用bool類型。因為If活動的Condition屬性的值不是true就是false。這種運算式是通過lambda運算式實現的(類似LINQ的文法),用來從工作流程運行時環境中擷取資料。在一個lambda運算式中,=>是lambda運算子。左邊的是輸入參數,實際的表達被放置在Lambda 運算子的右邊。運行時支援env的值,當判斷Condition的時候.

    工作流程實際上是沒有狀態的,它不儲存資料元素。Variable類是簡單的資料類型的定義。若要從一個Variable 變數中擷取實際資料,您將使用它的Get()方法。這還需要一個ActivityContext類對象。這是用來區分特定的工作流程執行個體,因為當前會運行一些其它工作流程執行個體。比較Get(env)的傳回值是否大於12。

    在While 活動中輸入下面的代碼:

DisplayName = "Sound Bells",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => counter.Get(env) <= numberBells.Get(env)),Body = new Sequence(){DisplayName = "Sound Bell"// Code to be added here in Level 3}

    While活動的Condition屬性和If活動的Condition屬性是相同的。它使用ExpressionServices類建立一個InArgument<T>類的對象,類型是bool。在這個例子中,用它來判斷count <= numberBells是否成立。對於這兩個變數,使用Get(env)方法來擷取實際的值。在第二個 If 活動(名為“Greeting”)輸入下面的代碼:

DisplayName = "Greeting",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => DateTime.Now.Hour >= 18),Then = new WriteLine() { Text = "Good Evening" },Else = new WriteLine() { Text = "Good Day" }

 

對於這個Condition中,雖然沒有使用到輸入參數env,但它還是必須在這個運算式中聲明。邏輯是判斷當前的時間是否超過下午6:00。在Then和Else屬性中,都添加一個WriteLine 活動。一個輸出“Good Evening”,另一個輸出“Good Day”。

實現層級3:

     對第一個If活動(名為“Adjust for PM”),你已經在它的Then屬性中添加了一個空的Assign活動。在Assign活動中輸入下面的實現的代碼:

DisplayName = "Adjust Bells",
// Code to be added here in Level 3
To = new OutArgument<int>(numberBells),
Value = new InArgument<int>(env => numberBells.Get(env) - 12)

Assign活動:

    Assign活動是通用的,它支援任何資料類型。在這個例子中,用它來分配整數值,所以它建立了一個Assign<int>類型的Assign活動。To和Value屬性也使用該模版類,所以他們應該是相同的類型(<int>)。To屬性的類型是一個OutArgument,在它建構函式中傳遞了一個Variable對象。Value屬性需要一個InArgument類型的對象。在if和while的Condition屬性之前,使用這個活動。和Condition屬性一樣,在它的建構函式中,使用了Lambda運算式,。

Sequence

    在While活動中,您已經建立一個空的Sequence活動。while迴圈每迭代一次,sequence活動裡面的子活動就將會被執行一次。輸入以下代碼來填充Activities屬性:

DisplayName = "Sound Bell",// Code to be added here in Level 3Activities ={new WriteLine(){Text = new InArgument<string>(env => counter.Get(env).ToString())},new Assign<int>(){DisplayName = "Increment Counter",To = new OutArgument<int>(counter),Value = new InArgument<int>(env => counter.Get(env) + 1)},new Delay(){Duration = TimeSpan.FromSeconds(1)}}

    這段代碼在Sequence中添加了三個活動:

WriteLine活動用於顯示counter

Assign活動用於增加counter的數量

Delay活動用於在迴圈中暫停流程一段時間

   這個WriteLine活動的Text屬性與其他的WriteLine活動不同,不是一個純字串。這個WriteLine活動中Text屬性被定義成一個運算式。由於Text屬性需要一個字串類型,所以我們給它建立了一個InArgument<string>類。現在,你可能已經習慣了這些Lambda運算式。Variable類的Get(env)方法返回一個int類型的值。ToString()方法將它轉換成字串。傳遞了一個由靜態方法FromSeconds() 建立的TimeSpan對象給Delay活動的Duration屬性。

運行應用程式

    按F5運行該應用程式。結果取決於一天的時間,您看起來應該類似這樣:

 

Hello, World!
1
2
3
4
5
6
7
The time is: 10/5/2009 7:02:41 PM
Good Evening
Press ENTER to exit

 

Program.cs完整實現代碼如清單2-2。

清單2-2.Program.cs

using System;using System.Activities;using System.Activities.Statements;using System.Activities.Expressions;namespace Chapter02{class Program{static void Main(string[] args){WorkflowInvoker.Invoke(CreateWorkflow());Console.WriteLine("Press ENTER to exit");Console.ReadLine();}static Activity CreateWorkflow(){Variable<int> numberBells = new Variable<int>(){Name = "numberBells",Default = DateTime.Now.Hour};Variable<int> counter = new Variable<int>(){Name = "counter",Default = 1};return new Sequence(){DisplayName = "Main Sequence",Variables = { numberBells, counter },Activities ={new WriteLine(){DisplayName = "Hello",},new If(){DisplayName = "Adjust for PM",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => numberBells.Get(env) > 12),Then = new Assign<int>(){DisplayName = "Adjust Bells",// Code to be added here in Level 3To = new OutArgument<int>(numberBells),Value = new InArgument<int>(env => numberBells.Get(env) - 12)}},new While(){DisplayName = "Sound Bells",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => counter.Get(env) <= numberBells.Get(env)),Body = new Sequence(){DisplayName = "Sound Bell",// Code to be added here in Level 3Activities ={new WriteLine(){Text = new InArgument<string>(env => counter.Get(env).ToString())},new Assign<int>(){DisplayName = "Increment Counter",To = new OutArgument<int>(counter),Value = new InArgument<int>(env => counter.Get(env) + 1)},new Delay(){Duration = TimeSpan.FromSeconds(1)}}}},new WriteLine(){DisplayName = "Display Time",Text = "The time is: " + DateTime.Now.ToString()},new If(){DisplayName = "Greeting",// Code to be added here in Level 2Condition = ExpressionServices.Convert<bool>(env => DateTime.Now.Hour >= 16),Then = new WriteLine() { Text = "Good Evening" },Else = new WriteLine() { Text = "Good Day" }}}};}}}

 

回顧

    本書有一些樣本是使用設計器的方式實現的,其他的是使用編碼的方式實現的。開始學習的時候,使用設計器的方式可能比使用編碼更容易接受和理解工作流程。但是,如果你對工作流程非常熟悉的時候,你可能會發現編碼的方式寫起來更快。兩種方式的最終結果是一樣的,兩種方法都非常地好。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.