程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WF4.0實戰(二十二):一個實際生活中狀態機的例子

WF4.0實戰(二十二):一個實際生活中狀態機的例子

編輯:關於.NET

這是實際生活中的一個狀態機的例子:“門”。這個例子是Mebyon Kernow寫的,使用狀態機對門的狀態進行控制,我覺得是學習WF4.0中 狀態機的好例子。所以,簡單的翻譯了他這篇文章。希望對你學習WF4.0的狀態機有所幫助。以下是正文。原文是:A practical State Machine example

現在,狀態機的活動已經發布在Codeplex上面了(詳見:http://wf.codeplex.com/)。我找出一個經常使用的例子。用這個例子用來演 示如何使用狀態機來控制一個建築物的進出(控制建築物的門),以及展示一下狀態機活動包中的主要功能。

這個例子的模型是對門的控制。宿主是一個WPF應用程序(WPF可以實現一些比較好的樣式!)。想象一下,如果你去'開啟'一個建築物 。此時,每一個門都是關閉或者鎖住的,這形成這個例子中狀態機初始化的狀態。因此,在狀態機中我們需要等待一個事件觸發來對門解鎖 ,現實中可能要使用密碼鍵盤或智能卡去開鎖。這個例子的狀態機的State和Transition如下圖所示:

當用戶提供自己的憑據來觸發上圖中的名字為Unlocked的Transition-這裡你可能需要你傳遞PIN號碼(或者卡上的號碼)給Transition , 然後再查詢數據庫進行驗證。這個例子中為了簡單起見,沒有任何驗證。

從ClosedLocked狀態出來,會存在三種可能性。一種是用戶打開門;一種是因為一些原因又鎖上門;一種是可能是他沒有打開門,一段時 間過後自動鎖上門,回到ClosedLocked狀態。在這個狀態上有三個Transition被執行,其中兩個是等到事件發生,第三種是用了一個Delay 活動,時間設置為5秒鐘。下面,我將會對State 和Transition進行解釋,它們對理解狀態機如何運作是至關重要的。

States & Transitions

一個狀態機由State的集合和State之間的transition集合構成的。必須有一個初始狀態,可以選擇是否有一個結束的狀態(完成了工作 流實例執行),當你進入一個State,你可以執行一些活動,同樣在退出一個State,的時候,還可以執行一些活動。要定義的Entry和Exit的 活動,雙擊State ,設計將顯示如下所示...

 

執行State活動的時候先執行Entry活動(它可以是一個Sequence ,這樣你就可以運行多個活動了)。接著是去尋找出這個State所有的 Transition。然後,執行每個Transition,這在我的狀態機例子中在活動執行中創建了書簽,然後等待恢復這個書簽。這似乎有些奇怪。如 果你有3個Transition,我們就要要為這三個分支設計觸發的活動。其實狀態機的引擎只需等待這些活動的一個完成,誰先誰執行,只要一 個觸發完成,這樣Transition就完成了。

理解Transition最簡單的方式是把它當作一個Pick活動看待。當狀態機處在一個給定的狀態,我們去執行每一個Transition的方式類似於 Pick活動處理方式,其中一個活動最先完成,Transition就完成。你可以在Transition上設置一些條件。這個時候,只有事件觸發而且條件 返回為True的時候,Transition才會完成。在ClosedLocked狀態中,Transition類似於下圖所示:

上圖中,我省略了Action,Transition分支和Pick活動稍微不同的地方。當Transition的觸發活動完成後,如果有創建Action活動,也將會 執行Action活動(假設條件返回為true)。

所以,在State中我們正等待一個活動的完成。在上圖中有一個自定義活動:DoorUnlocked和 DoorLocked活動。他們都是DoorEvent活動的實例,是由客戶端恢復的書簽。這項活動的代碼是相當簡單,如下...

public  class DoorEvent : NativeActivity 
{ 
  protected override bool CanInduceIdle 
  { 
     get { return true; } 
  } 
 
  [RequiredArgument] 
  public  InArgument<string> BookmarkName { get; set; } 
 
  protected override void Execute (NativeActivityContext context) 
  { 
    context.CreateBookmark(BookmarkName.Get(context), new  BookmarkCallback(OnBookmarkResumed)); 
  } 
 
  private void OnBookmarkResumed (NativeActivityContext context, Bookmark bookmark, object state) 
  { 
  } 
}

它有 一個必要的BookmarkName屬性,用來定義的書簽的名稱。在這個例子中,書簽的名稱和Transition的標簽相同。

在WPF中宿主

這個例子中宿主在WPF中,並使用MVVM模式(這裡只有一個View模型)來維護用戶界面。該用戶界面需要知道現在狀態機是什麼狀態,這 樣才能恢復正確的書簽,因此在每一個State的活動中我使用另外一個自定義活動將狀態機的狀態傳遞出來供View模型使用。這個狀態將更 新的View模型上的屬性。

在這個例子中,在視圖模型中使用了一些類 - MainViewModel類是應用程序的父類,它包含一組DoorModel實例,其中的一個表示UI上的 一道門。當DoorModel創建時,將創建 WorkflowApplication實例,並添加一個擴展到WorkflowApplication實例中(IDoor),這個擴展由 DoorModel實現。當通知模型狀態改變時,正是這種擴展,工作流將回到DoorModel中。該系統的偽代碼如下所示...

1、DoorModel實例被創建。設置它的名稱(顯示在屏幕上)。

2、在一個WorkflowApplication實例中創建一個狀態機實例。

3、狀態機啟動,並立即執行的第一個State活動'ClosedLocked'。這將先執行SetDoorState活動,並調用IDoor.SetState(),並給方法 傳遞一個枚舉值來說明狀態機是什麼狀態 。

4、根據工作流的狀態,使用enable/disable命令更新用戶界面。

此後,用戶界面負責管理狀態機。當一個命令,如'Unlock’被執行的,它只要在狀態機中恢復正確的書簽...

_unlockCommand = new DelegateCommand((unused) =>
   {
     _stateMachine.ResumeBookmark("Unlocked", null);
   },
   (unused) =>
   {
     return this.DoorState == DoorState.ClosedLocked;
   });

在這裡我使用的一個DelegateCommand類,這樣我可以使用lambda函數響應命令了。

當用戶點擊用戶界面,執行相應的命令來恢復書簽,完成流程中的一個Transition。進入一個新的狀態,回調到視圖模型,產生新的狀態 。

我還想說明的這個應用程序的例外一部分。在每一個Transition中使用了自定義的PlaySound活動。當Transition完成的時候,發出簡單 的聲音來表示門的狀態。這個例子中,當超時的時候,發出一種聲音。另外一種是門被鎖上的時候發出另外一種聲音。最初,我將聲音定義 在State活動的 ‘Entry’ 元素上面。這不能說明到底是哪一個transition是剛剛觸發的。即有沒有辦法區分狀態機是從哪一個Transition 進入 ClosedLocked中的,也就不能播放不同的聲音進入該活動了。

當您運行該應用程序你會看到下面的UI ...

如果你點擊Unlock 按鈕,就會執行工作流,改變狀態為ClosedUnlocked。你還會看到一組對應於現在有效狀態((Lock和Open)按鈕顯示 如果你解鎖一道門,然後離開約5秒鐘,門會自動再次鎖上。對於所有的Transition,您可以聽到一些聲音 - 如果你聽不到聲音,檢查每一 個Transition的PlaySound活動和選擇自己的文件播放(我在Windows 7文件目錄可能會和你的機子不同)。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved