《WF编程》系列之36 – 自定义活动:如何创建自定义活动?活动的组合

5.2 如何创建自定义活动?

有两种方式可以创建自定义活动,即通过组合的方式和使用继承的方式.

组合是一种简单的创建工作流的方式.我们在设计器中拖拽并配置活动的属性,然后把这个自定义活动封装成一个程序集,这样就可以供其它工作流项目使用了.这种方式的优点是快速并且简单.

使用继承的方式来创建自定义活动,我们需要编写一个类,并使其继承Activity类.也可以继承自Activity的子类从而获得更多的功能.我们可以自定义活动的设计视图,验证,序列化和代码生成.继承的方式允许我们对自定义活动进行更深层次的控制,并且提供了使用自定义代码来扩展Windows Workflow的途径.

5.3 活动的组合

让我们再回到经典的bug跟踪工作流,看看自定义活动能带给我们什么样的帮助.bug跟踪工作流需要针对bug去请求一份文档.为了这个文档,工作流需要和本地服务进行通信,所以它将实现以下接口:

[ExternalDataExchange]
interface IBugService
{
bool RequestUpload(Guid id, string userName);
event EventHandler UploadCompleted;
}

需要文档的工作流首先使用CallExternalMethod活动来调用ResuestUpload方法.紧接其后,工作流会使用HandleExternalEvent活动来等待UploadCompleted事件.我们需要插入并配置这两个活动到每一个需要请求文档的工作流中.所以我们的目标就是用一个自定义活动来替换这两个活动.

首先,我们创建一个工作流活动库,在New Project对话框中,选中Workflow Activity Library项目类型.这个项目类型会引用所有WF相关的程序集,并且可以生成的程序集可以被其它工作流项目引用.

活动库项目包含一个默认的活动(Activity1.cs),我们可以将其重命名为GetUpload.cs.这个活动使用纯代码的方式来编写.在第二章我们讨论过纯代码,纯XAML以及结合XAML和代码隐藏类这三种编写工作流的方式,这三种方式也同样适用于编写自定义活动.我们可以在New Item对话框中使用这几种方式添加新的活动.

在默认的情况下,自定义活动的根活动是一个SequentialActivity.在设计视图,我们可以从工具箱拖拽活动到设计器中.在下图中,我们添加了一个CallExternalMethod活动和一个HandleExternalEvent活动,然后配置这两个活动使它们分别调用RequestUpload方法和操作UploadCompleted事件.此时我们不需要配置任何方法和事件的参数.

现在编译一下活动库,会生成一个程序集文件.下一步,我们可以创建新的工作流项目并在其中使用这个程序集.在Visual Studio的File菜单中,点击Add>New Project.选择Sequential Workflow Console Application作为项目模板并为项目取名为Chapter5_workflows.想要使用刚才创建的自定义活动,我们需要右键单击新建的项目并选择Add Reference.在Projects选项卡中选择第一步时创建的活动库项目.

当我们开始设计工作流时,Visual Studio会找到我们引用的自定义活动并将其添加到工具箱中.在工作流设计视图中,我们的工具箱就会如下图所示:

在设计视图中,添加一个GetUploadActivity.注意我们的自定义活动内部的活动会显示出锁死的图标,这表示我们不能向通过组合的方式创建的自定义活动内部添加子活动(除非这个活动是空的).

现在才发现,我们不能修改自定义活动内部活动的属性.因为一个编译后的组合活动会变成一个”黑盒子”.我们无法向这个黑盒子中添加子活动,也无法删除或者修改里边的子活动.作为自定义活动的设计人员,需要认识到这一点.我们并不希望开发人员改变CallExternalMethod活动的InterfaseType或MethodName属性.因为改变这些属性可能会破坏GetUploadActivity原有的功能.我们的自定义活动需要保持完整性.

而对于自定义活动的使用者来说,黑盒引发了一个问题.在工作流内部,我们需要访问CallExternalMethod活动的id和userName参数,从而将正确的数据传递给宿主.如果工作流无法访问这些属性,那么自定义活动也就没有使用价值了.

作为自定义活动的编写人员,我们需要做的就是让这个组件可以使用.

下一节,让我们打开黑盒子,看看里边究竟有什么.

9 Comments

  1. ryan 1

    谢谢之前的帮助!
    我现在被1个问题难住了:同时运行多个workflow(xoml-only 顺序workflow包含一个自定义活动 )的时候,怎么样侦测 每个工作流的完成?

    我的目的是设置不同workflow的间隔时间,自动运行每个workflow。单个完成后,间隔段时间接着运行。并且各个workflow之间互不影响。每个工作流的dll,xoml路径从数据库中得到。

    我试过了threading.timer; 或通过得到instanid;OnWorkflowCompleted事件中检查。

  2. @ryan 1
    通过OnWorkflowCompleted事件来做,但是不能用instanceid来判断,因为instanceid每次都是不一样的,你得有自己的判断机制。
    就你的描述来看,这像是一个先进先出的队列,有思路了么?呵呵。

  3. ryan 1

    我是通过startworkflow之后接着把instanceid存报表中,然后在OnWorkflowCompleted中比较id。
    你说的没错,是先进先出,但是我找不到办法去得到instance,即使得到了怎么重新开始运行这个workflow?

    因为是工作要求,我搞了很长时间,烦的不行,杀人的心都有。博主能不能帮我写点在OnWorkflowCompleted中代码例子。发到我email��。
    我算跪求了。。。

  4. @ryan 1
    首先你要搞清楚工作流实例和工作流模板的区别。你的xoml文件叫做工作流模板,在代码中load成对象模型之后才叫做工作流实例。
    你的目的是接连不断的生成工作流模板的实例���然后运行,而不是把一个工作流实例运行多次。
    在OnWorkflowCompleted中可以得到刚刚完成的InstanceId,那么你就可以知道有一个工作流完成了,而且可以知道它的类型。
    那么在这时你难道就不能在new一个相同类型的工作流实例,然后启动它吗?

  5. ryan 1

    谢谢你的帮助,问题已经解决了, 基本思想和你的是一样啦。有些小细节没注意到。

  6. 他提示我错误 “Activity“handleExternalEventActivity1”验证失败: 事件 UploadCompleted 必须为 EventHandler 类型,这里的 T 派生自 ExternalDataEventArgs d:\wf\ActivityLibrary1\ActivityLibrary1\GetUpload.cs” 是怎么回事呀!(初学者,敬请谅解!!)

发表评论

电子邮件地址不会被公开。 必填项已用*标注