WF4.0实战(二十二):一个实际生活中状态机的例子
这是实际生活中的一个状态机的例子:“门”。这个例子是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文件目录可能会和你的机子不同)。
代码:https://files.cnblogs.com/zhuqil/Doors.rar
(全文完)
以下为广告部分
您部署的HTTPS网站安全吗?
如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!
快速了解HTTPS网站安全情况。
安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。
安装部署SSL证书变得更方便。
SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。
让服务器远离SSL证书漏洞侵扰
TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。