坚持学习WF(9):本地服务之事件处理

[置顶]坚持学习WF文章索引

一:先来介绍两个活动 EventDrivenActivity和 ListenActivity。

EventDrivenActivity是一个等侍事件触发的容器,EventDrivenActivity第一个子结点必需是一个继承 IEventActivity接口的Activity,后面所有的结点可以是任意Activity。该活动必须具有父级活动,它的父级活动可以是ListenActivity,StateActivity或StateMachineWorkflowActivity。

如果EventDrivenActvity在状态机工作流中使用,还有如下使用限制:

1. EventDrivenActivity 可以并且只能包含一个实现了IEventActivity接口的Activity.如HandleExternalEvent或Delay。
2. 如果有 HandleExternalEventActivity 必须是第一个结点.这是因为,Windows Workflow Foundation 实现的状态机工作流模型一次只处理一个EventDrivenActivity活动。例如,如果EventDrivenActivity 活动中包含多个能够运行的 IEventActivity 活动,则会出现以下情况:某个 EventDrivenActivity 活动在等待可能永远不会执行的IEventActivity 时被阻止。这样,状态机将无法处理任何其他消息。
3. 一个StateActivity状态容器可以有多个EventDrivenActivity。

ListenActivity属于单线触发容器,当某条分支中的结点执行完成后,该ListenActivity结点就结束,继续向下执行,其他分支内的结点就不执行了。EventDrivenActivity是它唯一可以添加的子活动,并且至少必须有两个子活动。该活动无法用于状态机工作流中。

二:工作流能够使用方法和事件通过消息与宿主程序交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序。在坚持学习WF(8):本地服务之调用外部方法这篇中我们说明了工作流如何使用本地服务来调用外部方法,接下来我们用一个猜数字游戏的小例子来主要说明在本地服务中如何使用事件。调用外部方法和事件处理基本的流程差不多。

1.实现事件参数类,GuessReceivedEventArgs类需要继承自ExternalDataEventArgs类,ExternalDataEventArgs类中的instanceId可以保证正确的工作流实例来接收事件。

 
ContractedBlock.gif ExpandedBlockStart.gif GuessReceivedEventArgs .cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Workflow.Activities;
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
InBlock.gif    [Serializable]
InBlock.gif    
public class GuessReceivedEventArgs : ExternalDataEventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private Int32 _nextGuess;
InBlock.gif
InBlock.gif        
public GuessReceivedEventArgs(Guid instanceId, Int32 nextGuess)
InBlock.gif            : 
base(instanceId)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            _nextGuess 
= nextGuess;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public Int32 NextGuess
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _nextGuess; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ _nextGuess = value; }
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

2.定义服务接口,代码如下

ContractedBlock.gif ExpandedBlockStart.gif IGuessingGame.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Workflow.Activities;
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
InBlock.gif    [ExternalDataExchange]
InBlock.gif    
public interface IGuessingGame
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{        
InBlock.gif        
void SendMessage(String message);       
InBlock.gif        
event EventHandler<GuessReceivedEventArgs> GuessReceived;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

3.实现本地服务,先定义一个事件参数。这个也继承自ExternalDataEventArgs,虽然它不是用在工作流中,但是我们为了使用InstanceId,所以也让它继承这个类。

ContractedBlock.gif ExpandedBlockStart.gif MessageReceivedEventArgs .cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Workflow.Activities;
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    [Serializable]
InBlock.gif    
public class MessageReceivedEventArgs : ExternalDataEventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private String _message;
InBlock.gif
InBlock.gif        
public MessageReceivedEventArgs(Guid instanceId, String message)
InBlock.gif            : 
base(instanceId)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            _message 
= message;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public String Message
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _message; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ _message = value; }
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


本地服务类,这类中共有四个成员:

SendMessage:workflow使用,由工作流实例来调用,发送一个信息到宿主程序,并且激发MessageReceive事件。

GuessReceived:workflow使用,接收下一个猜的数字,当OnGuessReceived方法调用的时候激发。

MessageReceived宿主使用,从工作流实例接收一个信息,通过SendMessage方法激发。

OnGussReceived:宿主使用,发送一个新的猜的数字到工作流,会引发GuessReceived事件。

注意:SendMessage方法使用静态的WorkflowEnvironment.WorkflowInstanceId方法取回工作流实例的ID,WorkflowEnvironment表示正在当前线程中运行的工作流实例的事务环境。

 
ContractedBlock.gif ExpandedBlockStart.gif GuessingGameService.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Workflow.Runtime;
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class GuessingGameService : IGuessingGame
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{       
InBlock.gif        
public void SendMessage(string message)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (MessageReceived != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                MessageReceivedEventArgs args
InBlock.gif                    
= new MessageReceivedEventArgs(
InBlock.gif                        WorkflowEnvironment.WorkflowInstanceId,
InBlock.gif                        message);
InBlock.gif                MessageReceived(
this, args);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }
        
InBlock.gif        
public event EventHandler<GuessReceivedEventArgs> GuessReceived;   
InBlock.gif        
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
InBlock.gif
InBlock.gif        
public void OnGuessReceived(GuessReceivedEventArgs args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (GuessReceived != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//must pass null as the sender otherwise
InBlock.gif                
//the correct workflow won't receive the event.
InBlock.gif
                GuessReceived(null, args);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

4.设计工作流,在工作流的Initialized事件中初始化这个要猜的随机数。
None.gif private   void  OnInitialized( object  sender, EventArgs e)
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
InBlock.gifRandom random 
= new Random();
InBlock.gif
InBlock.gif_theNumber 
= random.Next(110);
InBlock.gif
InBlock.gifMessage 
= "Please guess a number between 1 and 10.";
InBlock.gif
ExpandedBlockEnd.gif}

None.gif

Message属性给宿主的程序的暗示信息,指示猜的数字是大了还是小了。IsComplete属性是WhileActivity使用的,决定工作流是否完成了。

通过活动CallExternalMethodActivity设置InterfaceType和MethodName,还有message属性。

GuessReceived事件:在GuessReceived被激发的时候执行handleExternalEventActivity1_Invoked。该事件中决定用户的猜测是大了还是小了,为了完成工作流你必须处理该事件永远不发生的情况,我们要拖一个CodeActivity在右边的Event-Driven中,设置事件为一分钟,然后在拖一个TeminalActivity,如果一分钟内没猜的话就结束了。

完整的工作流如下图:

guesswf

完整代码如下

ContractedBlock.gif ExpandedBlockStart.gif GuessingGameWorkflow.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Workflow.Activities;
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// The guessing game workflow
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public sealed partial class GuessingGameWorkflow
InBlock.gif        : SequentialWorkflowActivity
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
Variables and Properties#region Variables and Properties
InBlock.gif
InBlock.gif        
private Int32 _theNumber;
InBlock.gif        
private Boolean _isComplete = false;
InBlock.gif        
private String _message = String.Empty;
InBlock.gif
InBlock.gif        
public String Message
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _message; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ _message = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public Boolean IsComplete
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _isComplete; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ _isComplete = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif        
public GuessingGameWorkflow()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            InitializeComponent();
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
InBlock.gif        
private void OnInitialized(object sender, EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Random random 
= new Random();
InBlock.gif            _theNumber 
= random.Next(110);
InBlock.gif            Message 
= "请输入1到10之间的某一个数字.";
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif       
InBlock.gif        
private void handleExternalEventActivity1_Invoked(
InBlock.gif            
object sender, ExternalDataEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            GuessReceivedEventArgs eventArgs
InBlock.gif                
= e as GuessReceivedEventArgs;
InBlock.gif            
if (eventArgs != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (eventArgs.NextGuess < _theNumber)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    Message 
= "请输入一个更大的数字.";
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else if (eventArgs.NextGuess > _theNumber)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    Message 
= "请输入一个更小的数字.";
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    Message 
= String.Format(
InBlock.gif                        
"恭喜您,猜对了{0}.", _theNumber);
InBlock.gif                    IsComplete 
= true;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

实现宿主程序,代码如下

ContractedBlock.gif ExpandedBlockStart.gif Form1.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifusing System;
None.gif
using System.Windows.Forms;
None.gif
None.gif
using System.Workflow.Activities;
None.gif
using System.Workflow.Runtime;
None.gif
None.gif
None.gif
namespace GuessNumber
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// The WinForm for the number guessing game
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public partial class Form1 : Form
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值