一步一步学WF系列(七)——改善登录程序(上)

1. 温故而知新

还记得我们在一步一步学WF系列(四)中写的登陆程序么?如果忘记了,那就回去看看。

在这一节中,让我们去改善我们的登录程序。

最近一直在忙着找工作的事情,所以发文慢了些,还望各位见谅。

3. 引出话题

我之前一直在强调,工作流负责的是一个宏观工作,我们应该把他与整体设计外的,那些边边角角的细节隔离在外面。

我最近在这个系列的同时,还在写一个《重温设计模式》的系列文章,因此特别要强调针对接口编程的重要性。

好,从现在开始步入正题。

4. 回顾登录

让我们回顾一下原有的登陆程序,在原有的登陆项目中,我们把所有的工作都杂糅在了工作流中。

让我们看看我们曾经丑陋的代码:

Workflow2.cs:

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    MessageBox.Show("用户名和密码不能为空");
}

private void Validate(object sender, ConditionalEventArgs e)
{
    e.Result = this.userName.Equals("admin") && this.userPassword.Equals("admin");
}

private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
    MessageBox.Show("登陆成功");
}

private void codeActivity3_ExecuteCode(object sender, EventArgs e)
{
    MessageBox.Show("用户名和密码不正确");
}

我想,当时也许有人会有这个疑问,楼主,你这不是骗人么?用不用工作流有什么呢?你不过是把原有的应该在Winform后台写的东西拿到了工作流中去写罢了。

好,我们从现在开始改善我们这段丑陋的代码。

5. 登录设计 

让我们先来想想我们在登录时的步骤,包括我们的做的和系统做的:

image

好,那么我们想,工作流负责的应该是一个宏观的过程,那么我们要把具体的细节给抽取出来,究竟什么是具体细节呢?

A. 用户的验证过程。(可能是连接数据库,可能是连接文件验证)

B. 反馈给客户的反馈信息。(可能是Response.Write,可能是MessageBox.Show)

好,抽取出了这两条,让我们想,是什么触发了这个工作流程,是我们点击登陆按钮的一刹那:

那么我们应该用一个事件去监听我们的登录按钮事件,当我们点击登录时便触发工作流。

分析结束,那就让我们看看我们的建模图:

image

由于本人的Visio功力实在有限,所以就用画图来画这些图了,我一定抓紧时间去练习Visio。

图画的不太好,我再来解释一下:

A. 用户首先输入用户名,密码,然后点击登录。

B. 这个时候触发了工作流的事件,并且向事件中传入我们所输入的信息。

C. 工作流根据我们所传入的信息去请求验证的接口,执行验证的代码。

D. 根据返回的结果,然后去请求相应的响应接口。

E. 最后将结果返回给用户。

分析结束,我们看到,这里面有个很重要的东西,就是工作流和外部的交互,好,那就让我们在改善登录程序前,先学习两个重要的活动。

6. HandlerExternalEvent

HandlerExternalEvent是我们接触的第一个事件类型的活动。事件类型就是通过某个事件才可以触发的活动。

我长话短说,这个活动的作用是在工作流的外部去调用工作流内部的方法,即HandlerExternalEvent的事件。

我在这里做一个小例子,然后结合代码为大家讲解。

首先让我们添加一个HandlerExternalEvent活动:

image

然后让我们新建一个类库,类库中包含一个接口,来做工作流和外部程序的一个交互:

namespace Interface
{
    [ExternalDataExchange]
    public interface IEvent
    {
        event EventHandler<ExternalDataEventArgs> MyEvent1;
    }
}

这段代码,我们注意三个点:

A. ExternalDataExchange:将接口标记为本地服务接口,具有该特性才能被工作流识别。

B. 接口内部事件:工作流在内部将自身绑定到该事件,用户在外部通过该事件触发工作流内部方法。

C. ExternalDataEventArgs:标识使用HandlerExternalEventActivity活动引发事件时传递的参数。

好,接下来我们通过属性窗口将该事件绑定到工作流的HandlerExternalEventActivity中:

image

然后我们在外部去调用这个事件,看整个项目的完整代码:

Workflow1.cs:

public sealed partial class Workflow1 : SequentialWorkflowActivity
{
    public Workflow1()
    {
        InitializeComponent();
    }

    private void handleExternalEventActivity1_Invoked(object sender, ExternalDataEventArgs e)
    {
        MessageBox.Show("Success");
    }
}

Winform1.cs:

public partial class Form1 : Form,IEvent
{
    private WorkflowRuntime runtime;
    private ExternalDataExchangeService service;
    private WorkflowInstance instance;
    public Form1()
    {
        InitializeComponent();
        runtime = new WorkflowRuntime();
        service = new ExternalDataExchangeService();
        runtime.AddService(service);
        service.AddService(this);
        runtime.StartRuntime();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        instance = runtime.CreateWorkflow(typeof(WorkflowConsoleApplication7.Workflow1));
        instance.Start();
        ExternalDataEventArgs args = new ExternalDataEventArgs(instance.InstanceId);
        MyEvent1(null, args);
    }


    #region IEvent 成员

    public event EventHandler<ExternalDataEventArgs> MyEvent1;

    #endregion
}

7. CallExternalMethod

与上面的活动相反,这个活动的作用是通过这个事件去调用外部的代码。

同样,我们用代码来说话:

image

接下来,我们同样来新建一个类库,包含一个接口用来和外部程序进行交互:

不同的是,在HandlerExternalEvent的接口中是事件,而这个是方法:

namespace CallMethod
{
    [ExternalDataExchange]
    public interface ICallExternalMethod
    {
        void CallExternalMethod();
    }
}

这个和上面都是一个道理的,我就不多做解释了:

让我们直接看代码吧:

image

Winform2.cs:

public partial class Form2 : Form,ICallExternalMethod
{
    private WorkflowRuntime runtime;
    private ExternalDataExchangeService service;
    private WorkflowInstance instance;
    public Form2()
    {
        InitializeComponent();
        runtime = new WorkflowRuntime();
        service = new ExternalDataExchangeService();
        runtime.AddService(service);
        service.AddService(this);
        runtime.StartRuntime();
    }

    #region ICallExternalMethod 成员

    public void CallExternalMethod()
    {
        MessageBox.Show("调用了这个方法");
    }

    #endregion

    private void button1_Click(object sender, EventArgs e)
    {
        instance = runtime.CreateWorkflow(typeof(WorkflowConsoleApplication7.Workflow2));
        instance.Start();
    }
}

8. 写在后面

本来想在这篇文章中完成对我们之前登录的改造,但是文章太长了大家好像都不太爱看,于是就还是分开写吧。

我们已经学习了如何让工作流和外部程序进行交互,那么我们大家就试着用这个去改善一下工作流吧?

你能么?

敬请期待下文:《一步一步学习WF系列(八)——改善登陆程序(下)》

posted @ 2009-04-23 02:05  飞林沙  阅读(2485)  评论(10编辑  收藏  举报