`

坚持学习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可以保证正确的工作流实例来接收事件。

GuessReceivedEventArgs .cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Workflow.Activities;

namespace GuessNumber
{
    
    [Serializable]
    
public class GuessReceivedEventArgs : ExternalDataEventArgs
    
{
        
private Int32 _nextGuess;

        
public GuessReceivedEventArgs(Guid instanceId, Int32 nextGuess)
            : 
base(instanceId)
        
{
            _nextGuess 
= nextGuess;
        }


        
public Int32 NextGuess
        
{
            
get return _nextGuess; }
            
set { _nextGuess = value; }
        }

    }

}

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

IGuessingGame.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Workflow.Activities;

namespace GuessNumber
{

    [ExternalDataExchange]
    
public interface IGuessingGame
    
{        
        
void SendMessage(String message);       
        
event EventHandler<GuessReceivedEventArgs> GuessReceived;
    }

}

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

MessageReceivedEventArgs .cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Workflow.Activities;

namespace GuessNumber
{
    [Serializable]
    
public class MessageReceivedEventArgs : ExternalDataEventArgs
    
{
        
private String _message;

        
public MessageReceivedEventArgs(Guid instanceId, String message)
            : 
base(instanceId)
        
{
            _message 
= message;
        }


        
public String Message
        
{
            
get return _message; }
            
set { _message = value; }
        }

    }

}


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

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

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

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

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

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

GuessingGameService.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Workflow.Runtime;

namespace GuessNumber
{
    
public class GuessingGameService : IGuessingGame
    
{       
        
public void SendMessage(string message)
        
{
            
if (MessageReceived != null)
            
{
                MessageReceivedEventArgs args
                    
= new MessageReceivedEventArgs(
                        WorkflowEnvironment.WorkflowInstanceId,
                        message);
                MessageReceived(
this, args);
            }

        }
        
        
public event EventHandler<GuessReceivedEventArgs> GuessReceived;   
        
public event EventHandler<MessageReceivedEventArgs> MessageReceived;

        
public void OnGuessReceived(GuessReceivedEventArgs args)
        
{
            
if (GuessReceived != null)
            
{
                
//must pass null as the sender otherwise
                
//the correct workflow won't receive the event.
                GuessReceived(null, args);
            }

        }

        
    }

}


4.设计工作流,在工作流的Initialized事件中初始化这个要猜的随机数。
private void OnInitialized(object sender, EventArgs e)

{

Random random 
= new Random();

_theNumber 
= random.Next(110);

Message 
= "Please guess a number between 1 and 10.";

}

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

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

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

完整的工作流如下图:

guesswf

完整代码如下

GuessingGameWorkflow.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Workflow.Activities;

namespace GuessNumber
{
    
/**//// <summary>
    
/// The guessing game workflow
    
/// </summary>

    public sealed partial class GuessingGameWorkflow
        : SequentialWorkflowActivity
    
{
        
Variables and Properties#region Variables and Properties

        
private Int32 _theNumber;
        
private Boolean _isComplete = false;
        
private String _message = String.Empty;

        
public String Message
        
{
            
get return _message; }
            
set { _message = value; }
        }


        
public Boolean IsComplete
        
{
            
get return _isComplete; }
            
set { _isComplete = value; }
        }


        
#endregion


        
public GuessingGameWorkflow()
        
{
            InitializeComponent();
        }


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


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

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

                
else
                
{
                    Message 
= String.Format(
                        
"恭喜您,猜对了{0}.", _theNumber);
                    IsComplete 
= true;
                }

            }

        }

    }

}

实现宿主程序,代码如下

Form1.cs
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->using System;
using System.Windows.Forms;

using System.Workflow.Activities;
using System.Workflow.Runtime;


namespace GuessNumber
{
    
/**//// <summary>
    
/// The WinForm for the number guessing game
    
/// </summary>

    public partial class Form1 : Form
    
{
        
color:
分享到:
评论

相关推荐

    WF教程_坚持学习WF

    坚持学习WF(1):从HelloWorld开始 本文主要通过实现了一个可以接受参数的HelloWorld程序来了解WF。 坚持学习WF(2):WF创作模式和设计时工具 坚持学习WF(3):WF框架概览 ...坚持学习WF(9):本地服务之事件处理

    坚持学习WF,WF学习教程

    坚持学习WF(9):本地服务之事件处理 工作流能够使用方法和事件通过消息与宿主程序交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序,8.9两篇主要说了本地服务如何调用外部方法和接收...

    坚持学习WF

    坚持学习WF(8):本地服务之调用外部方法 坚持学习WF(9):本地服务之事件处理 工作流能够使用方法和事件通过消息与宿主程序交互。 事件用于将数据发送到工作流,而工作流使用方法将数据发送到主机应用程序,8.9两篇...

    坚持学习WF(1):从HelloWorld开始 源码

    深入WF的学习,还需要掌握活动库的使用、自定义活动的创建、持久化机制、工作流服务(WF45中的WCF Workflow Service)以及与WF相关的设计模式。这将帮助你构建更复杂、灵活且适应性强的业务流程解决方案。 总结来说...

    坚持学习WF(5):自定义活动(CustomActivity) 源码

    自定义活动是WF强大之处,因为它使得开发者能够扩展WF的功能,以满足独特的需求。 二、创建自定义活动 1. 创建类:首先,你需要创建一个继承自`System.Activities.Activity`的类。这个类将成为你的自定义活动的基础...

    wf工作流资料<转自网上的笔记>

    "坚持学习WF(9)本地服务之事件处理"探讨了WF中的事件处理机制,这是工作流与外部系统交互的关键。这部分可能会讲解EventActivity以及如何使用事件触发工作流的行为。 "坚持学习WF(10)在工作流中使用关联"会涉及工作...

    WF工作流学习资料

    9. **WF的挑战与最佳实践**:尽管WF提供了强大的工作流支持,但理解和应用WF需要一定的学习曲线。最佳实践包括合理设计活动结构、充分利用持久化机制以及适当地使用跟踪和诊断功能。 通过深入学习WF工作流,开发者...

    Pro WF Windows Workflow in dot NET 3.5.pdf

    通过学习《Pro WF:Windows Workflow in .NET 3.5》,读者可以掌握如何利用WF设计和实现业务流程,包括创建自定义活动、调试工作流、实现工作流服务以及有效利用工作流持久化和规则引擎。此外,这本书还可能涵盖如何...

    Apress - Beginning WF: Windows Workflow in .NET 4.0 Mar 2010

    ### 关于《Apress - Beginning WF: Windows Workflow in .NET 4.0》的知识点解析 #### 一、概述 本书《Beginning WF: Windows Workflow in .NET 4.0》是一本详细介绍如何在.NET 4.0环境中使用Windows Workflow ...

    (2007 Apress)Pro WF Windows Workflow in .NET3.0.pdf

    - **事件驱动应用**:WF支持基于事件的工作流,适用于需要对特定事件做出响应的应用场景。 #### 4. 关键概念 - **活动(Activity)**:WF中的基本执行单元,代表了工作流的一部分逻辑。 - **工作流引擎**:负责解释...

    【翻译】WF从入门到精通(第一章):WF简介源代码下载

    5. **宿主环境**:学习如何在ASP.NET、Windows服务或其他应用环境中托管WF。 通过深入阅读WF的相关文档,结合PCodeFlow中的源代码实例,你将能够逐步精通WF,实现高效、灵活的业务流程管理。记住,实践是检验理论的...

    WF学习从入门到提高

    例如,你可能会学习如何在Visual Studio中创建第一个WF项目,如何使用各种内置活动,以及如何处理错误和异常。随着深入,你可能还会接触到高级主题,如自定义活动的开发,工作流服务(WCF Workflow Services)的实现...

    Microsoft WF 活动实例

    - **服务导向架构(SOA)**: 作为服务之间的协调者,处理服务间的交互逻辑。 - **实时监控系统**: 监控和管理系统的状态,根据预定义的规则触发相应的操作。 通过学习WF,开发者能够构建灵活、可扩展的业务流程,使...

    基于WF的工作流管理系统

    此外,WF还支持事件处理机制,通过外部事件接口与外界进行交互。 #### 三、WF技术架构 WF引擎采用三层架构设计,包括宿主层、运行时层和工作流模型层: ##### 3.1 宿主层 宿主层为WF和宿主应用程序之间提供必要的...

    pro wf windows workflow in dot net 3.5

    9. **工作流持久性框架**:介绍了WF的持久性接口和策略,以及如何实现自定义持久化提供者,以满足特定存储需求。 10. **案例研究**:书中可能包含多个实际应用场景,如订单处理、审批流程等,以帮助读者将理论知识...

    WF从入门到精通(第十七章):关联及本地主机通信(上)源码

    在本章节中,我们将深入探讨Windows ...通过研究这些源码,你可以更好地理解WF如何处理关联和本地通信,以及如何在实际项目中应用这些概念。在实践中,不断尝试和调试这些代码将加深你对WF的理解,进一步提升你的技能。

Global site tag (gtag.js) - Google Analytics